aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 14:13:26 +0200
committeraxis <qt-info@nokia.com>2011-04-27 14:40:44 +0200
commita129444bb0156c936900dbd2f12bd9f427ff366c (patch)
treee2e8e77f185d5a5ac32ea0a96cd9945c742e8663
parent885735d011472bcfbb96e688d9e64553d7fe9d4b (diff)
Initial import from qtquick2.
Branched from the monolithic repo, Qt qtquick2 branch, at commit a4a585d2ee907746682846ae6e8a48e19deef469
-rw-r--r--demos/declarative/plasmapatrol/PlasmaPatrol.qmlproject18
-rw-r--r--demos/declarative/plasmapatrol/TODO10
-rw-r--r--demos/declarative/plasmapatrol/content/BlasterHardpoint.qml133
-rw-r--r--demos/declarative/plasmapatrol/content/Button.qml66
-rw-r--r--demos/declarative/plasmapatrol/content/CannonHardpoint.qml97
-rw-r--r--demos/declarative/plasmapatrol/content/ChoiceBox.qml105
-rw-r--r--demos/declarative/plasmapatrol/content/Cruiser.qml146
-rw-r--r--demos/declarative/plasmapatrol/content/Frigate.qml114
-rw-r--r--demos/declarative/plasmapatrol/content/Hardpoint.qml112
-rw-r--r--demos/declarative/plasmapatrol/content/HelpScreens.qml268
-rw-r--r--demos/declarative/plasmapatrol/content/LaserHardpoint.qml108
-rw-r--r--demos/declarative/plasmapatrol/content/PlasmaPatrolParticles.qml173
-rw-r--r--demos/declarative/plasmapatrol/content/SequentialLoader.qml54
-rw-r--r--demos/declarative/plasmapatrol/content/Ship.qml113
-rw-r--r--demos/declarative/plasmapatrol/content/Sloop.qml108
-rw-r--r--demos/declarative/plasmapatrol/content/pics/TitleText.pngbin0 -> 1109 bytes
-rw-r--r--demos/declarative/plasmapatrol/content/pics/blur-circle2.pngbin0 -> 3627 bytes
-rw-r--r--demos/declarative/plasmapatrol/content/pics/blur-circle3.pngbin0 -> 5148 bytes
-rw-r--r--demos/declarative/plasmapatrol/content/pics/finalfrontier.pngbin0 -> 695061 bytes
-rw-r--r--demos/declarative/plasmapatrol/content/pics/meteor.pngbin0 -> 83169 bytes
-rw-r--r--demos/declarative/plasmapatrol/content/pics/meteor_explo.pngbin0 -> 81528 bytes
-rw-r--r--demos/declarative/plasmapatrol/content/pics/nullRock.pngbin0 -> 140 bytes
-rw-r--r--demos/declarative/plasmapatrol/content/pics/particle.pngbin0 -> 861 bytes
-rw-r--r--demos/declarative/plasmapatrol/content/pics/star.pngbin0 -> 1550 bytes
-rw-r--r--demos/declarative/plasmapatrol/content/pics/star2.pngbin0 -> 6507 bytes
-rw-r--r--demos/declarative/plasmapatrol/content/pics/star3.pngbin0 -> 4602 bytes
-rw-r--r--demos/declarative/plasmapatrol/plasmapatrol.qml386
-rw-r--r--demos/declarative/samegame/SamegameCore/BoomBlock.qml36
-rw-r--r--demos/declarative/samegame/SamegameCore/Button.qml2
-rw-r--r--demos/declarative/samegame/SamegameCore/Dialog.qml7
-rw-r--r--demos/declarative/samegame/SamegameCore/pics/blueStar.pngbin278 -> 0 bytes
-rw-r--r--demos/declarative/samegame/SamegameCore/pics/greenStar.pngbin273 -> 0 bytes
-rw-r--r--demos/declarative/samegame/SamegameCore/pics/particle.pngbin0 -> 861 bytes
-rw-r--r--demos/declarative/samegame/SamegameCore/pics/redStar.pngbin274 -> 0 bytes
-rw-r--r--demos/declarative/samegame/SamegameCore/pics/star.pngbin262 -> 0 bytes
-rwxr-xr-xdemos/declarative/samegame/SamegameCore/samegame.js43
-rw-r--r--demos/declarative/samegame/samegame.qml35
-rw-r--r--demos/declarative/shadereffects/Slider.qml93
-rw-r--r--demos/declarative/shadereffects/face-smile.pngbin0 -> 15408 bytes
-rw-r--r--demos/declarative/shadereffects/qt-logo.pngbin0 -> 13923 bytes
-rw-r--r--demos/declarative/shadereffects/shader-demo.qml295
-rw-r--r--doc/src/declarative/modules.qdoc123
-rw-r--r--doc/src/declarative/qdeclarativeintro.qdoc8
-rw-r--r--doc/src/snippets/declarative/models/views-models-delegates.qml1
-rw-r--r--doc/src/snippets/declarative/models/visual-model-and-view.qml1
-rw-r--r--doc/src/snippets/declarative/mousearea/mousearea-snippet.qml2
-rw-r--r--doc/src/snippets/declarative/states/statechangescript.qml1
-rw-r--r--examples/declarative/declarative.pro3
-rw-r--r--examples/declarative/inputmethods/inputmethods.qmlproject16
-rw-r--r--examples/declarative/inputmethods/spellcheck/Key.qml85
-rw-r--r--examples/declarative/inputmethods/spellcheck/Keyboard.qml141
-rw-r--r--examples/declarative/inputmethods/spellcheck/WordSuggestions.qml100
-rw-r--r--examples/declarative/inputmethods/spellcheck/spellcheck.qml137
-rw-r--r--examples/declarative/painteditem/main.cpp80
-rw-r--r--examples/declarative/painteditem/myfile.qml57
-rw-r--r--examples/declarative/painteditem/painteditem.pro14
-rw-r--r--examples/declarative/particles/allsmiles/content/particle.pngbin0 -> 861 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/singlesmile.pngbin0 -> 269 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/sizeInOut.pngbin0 -> 251 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/smileMask.pngbin0 -> 259 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/squarefacesprite.pngbin0 -> 496 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/squarefacesprite2.pngbin0 -> 459 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/squarefacesprite3.pngbin0 -> 476 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/squarefacesprite4.pngbin0 -> 553 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/squarefacesprite5.pngbin0 -> 623 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/squarefacesprite6.pngbin0 -> 615 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/squarefacesprite7.pngbin0 -> 581 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/squarefacespriteX.pngbin0 -> 474 bytes
-rw-r--r--examples/declarative/particles/allsmiles/content/squarefacespriteXX.pngbin0 -> 255 bytes
-rw-r--r--examples/declarative/particles/allsmiles/smile.qml77
-rw-r--r--examples/declarative/particles/allsmiles/smilefactory.qml117
-rw-r--r--examples/declarative/particles/allsmiles/spriteparticles.qml103
-rw-r--r--examples/declarative/particles/allsmiles/spritestateparticles.qml190
-rw-r--r--examples/declarative/particles/allsmiles/spritevariedparticles.qml117
-rw-r--r--examples/declarative/particles/asteroid/asteroid.qml213
-rw-r--r--examples/declarative/particles/asteroid/blackhole.qml200
-rw-r--r--examples/declarative/particles/asteroid/content/_explo.pngbin0 -> 81528 bytes
-rw-r--r--examples/declarative/particles/asteroid/content/finalfrontier.pngbin0 -> 695061 bytes
-rw-r--r--examples/declarative/particles/asteroid/content/meteor.pngbin0 -> 83169 bytes
-rw-r--r--examples/declarative/particles/asteroid/content/meteor_explo.pngbin0 -> 219946 bytes
-rw-r--r--examples/declarative/particles/asteroid/content/meteors.pngbin0 -> 132137 bytes
-rw-r--r--examples/declarative/particles/asteroid/content/nullRock.pngbin0 -> 140 bytes
-rw-r--r--examples/declarative/particles/asteroid/content/particle4.pngbin0 -> 1799 bytes
-rw-r--r--examples/declarative/particles/asteroid/content/rocket.pngbin0 -> 7315 bytes
-rw-r--r--examples/declarative/particles/asteroid/content/rocket2.pngbin0 -> 1918 bytes
-rw-r--r--examples/declarative/particles/asteroid/content/star.pngbin0 -> 1550 bytes
-rw-r--r--examples/declarative/particles/modelparticles/bubbles.qml81
-rw-r--r--examples/declarative/particles/modelparticles/content/Delegate.qml88
-rw-r--r--examples/declarative/particles/modelparticles/content/Delegate2.qml79
-rw-r--r--examples/declarative/particles/modelparticles/content/ExpandingDelegate.qml204
-rw-r--r--examples/declarative/particles/modelparticles/content/RssModel.qml53
-rw-r--r--examples/declarative/particles/modelparticles/content/bubble.pngbin0 -> 3413 bytes
-rw-r--r--examples/declarative/particles/modelparticles/content/script.js27
-rw-r--r--examples/declarative/particles/modelparticles/gridsplosion.qml146
-rw-r--r--examples/declarative/particles/modelparticles/package.qml91
-rw-r--r--examples/declarative/particles/modelparticles/stream.qml280
-rw-r--r--examples/declarative/particles/snow/content/flake-01.pngbin0 -> 189327 bytes
-rw-r--r--examples/declarative/particles/snow/snow.qml75
-rw-r--r--examples/declarative/particles/snow/snow2.qml74
-rw-r--r--examples/declarative/particles/snow/snow3.qml80
-rw-r--r--examples/declarative/particles/spaceexplorer/content/helpers.js8
-rw-r--r--examples/declarative/particles/spaceexplorer/content/particle4.pngbin0 -> 1799 bytes
-rw-r--r--examples/declarative/particles/spaceexplorer/content/powerupScore.pngbin0 -> 83169 bytes
-rw-r--r--examples/declarative/particles/spaceexplorer/content/powerupScore_gone.pngbin0 -> 140 bytes
-rw-r--r--examples/declarative/particles/spaceexplorer/content/powerupScore_got.pngbin0 -> 81528 bytes
-rw-r--r--examples/declarative/particles/spaceexplorer/content/rocket.pngbin0 -> 7315 bytes
-rw-r--r--examples/declarative/particles/spaceexplorer/content/rocket2.pngbin0 -> 1918 bytes
-rw-r--r--examples/declarative/particles/spaceexplorer/content/rocketEye.pngbin0 -> 2073 bytes
-rw-r--r--examples/declarative/particles/spaceexplorer/content/star.pngbin0 -> 1550 bytes
-rw-r--r--examples/declarative/particles/spaceexplorer/spaceexplorer.qml412
-rw-r--r--examples/declarative/particles/trails/content/PetsModel.qml98
-rw-r--r--examples/declarative/particles/trails/content/candle.pngbin0 -> 1348 bytes
-rw-r--r--examples/declarative/particles/trails/content/colortable.pngbin0 -> 704 bytes
-rw-r--r--examples/declarative/particles/trails/content/particle.pngbin0 -> 861 bytes
-rw-r--r--examples/declarative/particles/trails/content/particle2.pngbin0 -> 3909 bytes
-rw-r--r--examples/declarative/particles/trails/content/particle3.pngbin0 -> 3186 bytes
-rw-r--r--examples/declarative/particles/trails/content/particleA.pngbin0 -> 3541 bytes
-rw-r--r--examples/declarative/particles/trails/content/portal_bg.pngbin0 -> 96858 bytes
-rw-r--r--examples/declarative/particles/trails/content/sparkleSize.pngbin0 -> 378 bytes
-rw-r--r--examples/declarative/particles/trails/content/star.pngbin0 -> 1550 bytes
-rw-r--r--examples/declarative/particles/trails/dynamicemitters.qml121
-rw-r--r--examples/declarative/particles/trails/fireballs.qml174
-rw-r--r--examples/declarative/particles/trails/layered.qml93
-rw-r--r--examples/declarative/particles/trails/list.qml120
-rw-r--r--examples/declarative/particles/trails/overburst.qml85
-rw-r--r--examples/declarative/particles/trails/portal.qml110
-rw-r--r--examples/declarative/particles/trails/rainbow.qml82
-rw-r--r--examples/declarative/particles/trails/shimmer.qml73
-rw-r--r--examples/declarative/particles/trails/swarm.qml78
-rw-r--r--examples/declarative/particles/trails/trails.qml87
-rw-r--r--examples/declarative/particles/trails/turbulence.qml129
-rw-r--r--examples/declarative/particles/trails/velocityfrommotion.qml327
-rw-r--r--src/declarative/debugger/qdeclarativedebug.cpp46
-rw-r--r--src/declarative/debugger/qdeclarativedebugserver.cpp50
-rw-r--r--src/declarative/debugger/qdeclarativedebugserver_p.h3
-rw-r--r--src/declarative/debugger/qdeclarativedebugserverconnection_p.h1
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice.cpp10
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice_p.h2
-rw-r--r--src/declarative/debugger/qdeclarativedebugtrace.cpp9
-rw-r--r--src/declarative/debugger/qdeclarativedebugtrace_p.h1
-rw-r--r--src/declarative/debugger/qpacketprotocol.cpp49
-rw-r--r--src/declarative/debugger/qpacketprotocol_p.h2
-rw-r--r--src/declarative/declarative.pro2
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem.cpp48
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem_p.h11
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit.cpp3
-rwxr-xr-xsrc/declarative/items/checksync.pl108
-rw-r--r--src/declarative/items/items.pri109
-rw-r--r--src/declarative/items/qsganchors.cpp1111
-rw-r--r--src/declarative/items/qsganchors_p.h201
-rw-r--r--src/declarative/items/qsganchors_p_p.h173
-rw-r--r--src/declarative/items/qsganimatedimage.cpp304
-rw-r--r--src/declarative/items/qsganimatedimage_p.h117
-rw-r--r--src/declarative/items/qsganimatedimage_p_p.h88
-rw-r--r--src/declarative/items/qsganimation.cpp442
-rw-r--r--src/declarative/items/qsganimation_p.h132
-rw-r--r--src/declarative/items/qsganimation_p_p.h97
-rw-r--r--src/declarative/items/qsgborderimage.cpp359
-rw-r--r--src/declarative/items/qsgborderimage_p.h110
-rw-r--r--src/declarative/items/qsgborderimage_p_p.h109
-rw-r--r--src/declarative/items/qsgcanvas.cpp1890
-rw-r--r--src/declarative/items/qsgcanvas.h118
-rw-r--r--src/declarative/items/qsgcanvas_p.h195
-rw-r--r--src/declarative/items/qsgclipnode.cpp121
-rw-r--r--src/declarative/items/qsgclipnode_p.h71
-rw-r--r--src/declarative/items/qsgevents.cpp47
-rw-r--r--src/declarative/items/qsgevents_p_p.h142
-rw-r--r--src/declarative/items/qsgflickable.cpp1397
-rw-r--r--src/declarative/items/qsgflickable_p.h230
-rw-r--r--src/declarative/items/qsgflickable_p_p.h231
-rw-r--r--src/declarative/items/qsgflipable.cpp255
-rw-r--r--src/declarative/items/qsgflipable_p.h104
-rw-r--r--src/declarative/items/qsgfocusscope.cpp57
-rw-r--r--src/declarative/items/qsgfocusscope_p.h68
-rw-r--r--src/declarative/items/qsggridview.cpp2634
-rw-r--r--src/declarative/items/qsggridview_p.h290
-rw-r--r--src/declarative/items/qsgimage.cpp288
-rw-r--r--src/declarative/items/qsgimage_p.h104
-rw-r--r--src/declarative/items/qsgimage_p_p.h81
-rw-r--r--src/declarative/items/qsgimagebase.cpp273
-rw-r--r--src/declarative/items/qsgimagebase_p.h116
-rw-r--r--src/declarative/items/qsgimagebase_p_p.h93
-rw-r--r--src/declarative/items/qsgimplicitsizeitem.cpp93
-rw-r--r--src/declarative/items/qsgimplicitsizeitem_p.h101
-rw-r--r--src/declarative/items/qsgimplicitsizeitem_p_p.h92
-rw-r--r--src/declarative/items/qsgitem.cpp3143
-rw-r--r--src/declarative/items/qsgitem.h399
-rw-r--r--src/declarative/items/qsgitem_p.h710
-rw-r--r--src/declarative/items/qsgitemchangelistener_p.h82
-rw-r--r--src/declarative/items/qsgitemsmodule.cpp205
-rw-r--r--src/declarative/items/qsgitemsmodule_p.h65
-rw-r--r--src/declarative/items/qsglistview.cpp3032
-rw-r--r--src/declarative/items/qsglistview_p.h374
-rw-r--r--src/declarative/items/qsgloader.cpp340
-rw-r--r--src/declarative/items/qsgloader_p.h107
-rw-r--r--src/declarative/items/qsgloader_p_p.h91
-rw-r--r--src/declarative/items/qsgmousearea.cpp771
-rw-r--r--src/declarative/items/qsgmousearea_p.h216
-rw-r--r--src/declarative/items/qsgmousearea_p_p.h112
-rw-r--r--src/declarative/items/qsgninepatchnode.cpp273
-rw-r--r--src/declarative/items/qsgninepatchnode_p.h94
-rw-r--r--src/declarative/items/qsgpainteditem.cpp354
-rw-r--r--src/declarative/items/qsgpainteditem.h119
-rw-r--r--src/declarative/items/qsgpainteditem_p.h67
-rw-r--r--src/declarative/items/qsgpathview.cpp1410
-rw-r--r--src/declarative/items/qsgpathview_p.h254
-rw-r--r--src/declarative/items/qsgpathview_p_p.h193
-rw-r--r--src/declarative/items/qsgpincharea.cpp407
-rw-r--r--src/declarative/items/qsgpincharea_p.h310
-rw-r--r--src/declarative/items/qsgpincharea_p_p.h112
-rw-r--r--src/declarative/items/qsgpositioners.cpp788
-rw-r--r--src/declarative/items/qsgpositioners_p.h242
-rw-r--r--src/declarative/items/qsgpositioners_p_p.h173
-rw-r--r--src/declarative/items/qsgrectangle.cpp286
-rw-r--r--src/declarative/items/qsgrectangle_p.h184
-rw-r--r--src/declarative/items/qsgrectangle_p_p.h109
-rw-r--r--src/declarative/items/qsgrepeater.cpp294
-rw-r--r--src/declarative/items/qsgrepeater_p.h111
-rw-r--r--src/declarative/items/qsgrepeater_p_p.h83
-rw-r--r--src/declarative/items/qsgscalegrid.cpp213
-rw-r--r--src/declarative/items/qsgscalegrid_p_p.h134
-rw-r--r--src/declarative/items/qsgshadereffectitem.cpp449
-rw-r--r--src/declarative/items/qsgshadereffectitem_p.h159
-rw-r--r--src/declarative/items/qsgshadereffectmesh.cpp167
-rw-r--r--src/declarative/items/qsgshadereffectmesh_p.h102
-rw-r--r--src/declarative/items/qsgshadereffectnode.cpp322
-rw-r--r--src/declarative/items/qsgshadereffectnode_p.h148
-rw-r--r--src/declarative/items/qsgshadereffectsource.cpp526
-rw-r--r--src/declarative/items/qsgshadereffectsource_p.h219
-rw-r--r--src/declarative/items/qsgstateoperations.cpp1347
-rw-r--r--src/declarative/items/qsgstateoperations_p.h275
-rw-r--r--src/declarative/items/qsgtext.cpp1240
-rw-r--r--src/declarative/items/qsgtext_p.h214
-rw-r--r--src/declarative/items/qsgtext_p_p.h154
-rw-r--r--src/declarative/items/qsgtextedit.cpp1235
-rw-r--r--src/declarative/items/qsgtextedit_p.h303
-rw-r--r--src/declarative/items/qsgtextedit_p_p.h143
-rw-r--r--src/declarative/items/qsgtextinput.cpp1265
-rw-r--r--src/declarative/items/qsgtextinput_p.h299
-rw-r--r--src/declarative/items/qsgtextinput_p_p.h150
-rw-r--r--src/declarative/items/qsgtextnode.cpp457
-rw-r--r--src/declarative/items/qsgtextnode_p.h84
-rw-r--r--src/declarative/items/qsgtranslate.cpp297
-rw-r--r--src/declarative/items/qsgtranslate_p.h162
-rw-r--r--src/declarative/items/qsgview.cpp466
-rw-r--r--src/declarative/items/qsgview.h120
-rw-r--r--src/declarative/items/qsgvisualitemmodel.cpp1247
-rw-r--r--src/declarative/items/qsgvisualitemmodel_p.h257
-rw-r--r--src/declarative/items/syncexcludes11
-rw-r--r--src/declarative/qml/qdeclarative.h33
-rw-r--r--src/declarative/qml/qdeclarativebinding.cpp19
-rw-r--r--src/declarative/qml/qdeclarativecompiledbindings.cpp2906
-rw-r--r--src/declarative/qml/qdeclarativecompileddata.cpp3
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp149
-rw-r--r--src/declarative/qml/qdeclarativecompiler_p.h5
-rw-r--r--src/declarative/qml/qdeclarativecomponent.cpp39
-rw-r--r--src/declarative/qml/qdeclarativecomponent.h1
-rw-r--r--src/declarative/qml/qdeclarativecontext.cpp84
-rw-r--r--src/declarative/qml/qdeclarativecontext_p.h11
-rw-r--r--src/declarative/qml/qdeclarativedirparser.cpp23
-rw-r--r--src/declarative/qml/qdeclarativedirparser_p.h16
-rw-r--r--src/declarative/qml/qdeclarativedom.cpp1835
-rw-r--r--src/declarative/qml/qdeclarativedom_p.h362
-rw-r--r--src/declarative/qml/qdeclarativedom_p_p.h157
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp132
-rw-r--r--src/declarative/qml/qdeclarativeengine.h3
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h25
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp7
-rw-r--r--src/declarative/qml/qdeclarativeimageprovider.cpp33
-rw-r--r--src/declarative/qml/qdeclarativeimageprovider.h5
-rw-r--r--src/declarative/qml/qdeclarativeimport.cpp208
-rw-r--r--src/declarative/qml/qdeclarativeimport_p.h6
-rw-r--r--src/declarative/qml/qdeclarativeinfo.cpp12
-rw-r--r--src/declarative/qml/qdeclarativeinstruction.cpp3
-rw-r--r--src/declarative/qml/qdeclarativeinstruction_p.h7
-rw-r--r--src/declarative/qml/qdeclarativemetatype.cpp96
-rw-r--r--src/declarative/qml/qdeclarativemetatype_p.h39
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass.cpp27
-rw-r--r--src/declarative/qml/qdeclarativeprivate.h17
-rw-r--r--src/declarative/qml/qdeclarativepropertycache.cpp2
-rw-r--r--src/declarative/qml/qdeclarativepropertycache_p.h21
-rw-r--r--src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp193
-rw-r--r--src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h163
-rw-r--r--src/declarative/qml/qdeclarativescriptparser.cpp47
-rw-r--r--src/declarative/qml/qdeclarativescriptparser_p.h2
-rw-r--r--src/declarative/qml/qdeclarativetypeloader.cpp244
-rw-r--r--src/declarative/qml/qdeclarativetypeloader_p.h62
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache.cpp8
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache_p.h16
-rw-r--r--src/declarative/qml/qdeclarativetypenamescriptclass.cpp38
-rw-r--r--src/declarative/qml/qdeclarativetypenamescriptclass_p.h1
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp82
-rw-r--r--src/declarative/qml/qdeclarativevme_p.h4
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject.cpp10
-rw-r--r--src/declarative/qml/qdeclarativexmlhttprequest.cpp21
-rw-r--r--src/declarative/qml/qintrusivelist.cpp173
-rw-r--r--src/declarative/qml/qintrusivelist_p.h254
-rw-r--r--src/declarative/qml/qmetaobjectbuilder.cpp57
-rw-r--r--src/declarative/qml/qmetaobjectbuilder_p.h4
-rw-r--r--src/declarative/qml/qml.pri14
-rw-r--r--src/declarative/qml/v4/qdeclarativev4bindings.cpp1530
-rw-r--r--src/declarative/qml/v4/qdeclarativev4bindings_p.h92
-rw-r--r--src/declarative/qml/v4/qdeclarativev4compiler.cpp1340
-rw-r--r--src/declarative/qml/v4/qdeclarativev4compiler_p.h (renamed from src/declarative/qml/qdeclarativecompiledbindings_p.h)38
-rw-r--r--src/declarative/qml/v4/qdeclarativev4compiler_p_p.h184
-rw-r--r--src/declarative/qml/v4/qdeclarativev4instruction.cpp559
-rw-r--r--src/declarative/qml/v4/qdeclarativev4instruction_p.h444
-rw-r--r--src/declarative/qml/v4/qdeclarativev4ir.cpp832
-rw-r--r--src/declarative/qml/v4/qdeclarativev4ir_p.h546
-rw-r--r--src/declarative/qml/v4/qdeclarativev4irbuilder.cpp1315
-rw-r--r--src/declarative/qml/v4/qdeclarativev4irbuilder_p.h242
-rw-r--r--src/declarative/qml/v4/qdeclarativev4program_p.h122
-rw-r--r--src/declarative/qml/v4/v4.pri17
-rw-r--r--src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp458
-rw-r--r--src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h96
-rw-r--r--src/declarative/scenegraph/coreapi/qsggeometry.cpp310
-rw-r--r--src/declarative/scenegraph/coreapi/qsggeometry.h254
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmaterial.cpp199
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmaterial.h141
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp380
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h104
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h73
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnode.cpp837
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnode.h363
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp243
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h87
-rw-r--r--src/declarative/scenegraph/coreapi/qsgrenderer.cpp545
-rw-r--r--src/declarative/scenegraph/coreapi/qsgrenderer_p.h219
-rw-r--r--src/declarative/scenegraph/qsgadaptationlayer.cpp42
-rw-r--r--src/declarative/scenegraph/qsgadaptationlayer_p.h123
-rw-r--r--src/declarative/scenegraph/qsgcontext.cpp428
-rw-r--r--src/declarative/scenegraph/qsgcontext_p.h124
-rw-r--r--src/declarative/scenegraph/qsgcontextplugin.cpp104
-rw-r--r--src/declarative/scenegraph/qsgcontextplugin_p.h81
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode.cpp95
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp313
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode_p.h83
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h95
-rw-r--r--src/declarative/scenegraph/qsgdefaultimagenode.cpp181
-rw-r--r--src/declarative/scenegraph/qsgdefaultimagenode_p.h90
-rw-r--r--src/declarative/scenegraph/qsgdefaultrectanglenode.cpp550
-rw-r--r--src/declarative/scenegraph/qsgdefaultrectanglenode_p.h106
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp956
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h159
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp223
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp656
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h93
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h128
-rw-r--r--src/declarative/scenegraph/qsgflashnode.cpp62
-rw-r--r--src/declarative/scenegraph/qsgflashnode_p.h69
-rw-r--r--src/declarative/scenegraph/scenegraph.pri80
-rw-r--r--src/declarative/scenegraph/util/qsgareaallocator.cpp290
-rw-r--r--src/declarative/scenegraph/util/qsgareaallocator_p.h73
-rw-r--r--src/declarative/scenegraph/util/qsgengine.cpp244
-rw-r--r--src/declarative/scenegraph/util/qsgengine.h100
-rw-r--r--src/declarative/scenegraph/util/qsgflatcolormaterial.cpp140
-rw-r--r--src/declarative/scenegraph/util/qsgflatcolormaterial.h71
-rw-r--r--src/declarative/scenegraph/util/qsgpainternode.cpp379
-rw-r--r--src/declarative/scenegraph/util/qsgpainternode_p.h140
-rw-r--r--src/declarative/scenegraph/util/qsgsimplerectnode.cpp132
-rw-r--r--src/declarative/scenegraph/util/qsgsimplerectnode.h77
-rw-r--r--src/declarative/scenegraph/util/qsgsimpletexturenode.cpp152
-rw-r--r--src/declarative/scenegraph/util/qsgsimpletexturenode.h82
-rw-r--r--src/declarative/scenegraph/util/qsgtexture.cpp403
-rw-r--r--src/declarative/scenegraph/util/qsgtexture.h135
-rw-r--r--src/declarative/scenegraph/util/qsgtexture_p.h111
-rw-r--r--src/declarative/scenegraph/util/qsgtexturematerial.cpp200
-rw-r--r--src/declarative/scenegraph/util/qsgtexturematerial.h100
-rw-r--r--src/declarative/scenegraph/util/qsgtexturematerial_p.h73
-rw-r--r--src/declarative/scenegraph/util/qsgtextureprovider.cpp65
-rw-r--r--src/declarative/scenegraph/util/qsgtextureprovider_p.h70
-rw-r--r--src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp136
-rw-r--r--src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h73
-rw-r--r--src/declarative/util/qdeclarativepixmapcache.cpp197
-rw-r--r--src/declarative/util/qdeclarativepixmapcache_p.h4
-rw-r--r--src/imports/etcprovider/etcprovider.pro19
-rw-r--r--src/imports/etcprovider/plugin.cpp72
-rw-r--r--src/imports/etcprovider/plugin.h (renamed from src/imports/particles/particles.cpp)31
-rw-r--r--src/imports/etcprovider/qetcprovider.cpp185
-rw-r--r--src/imports/etcprovider/qetcprovider.h100
-rw-r--r--src/imports/etcprovider/qmldir1
-rw-r--r--src/imports/imports.pro2
-rw-r--r--src/imports/inputcontext/declarativeinputcontext.cpp199
-rw-r--r--src/imports/inputcontext/declarativeinputcontext.h104
-rwxr-xr-xsrc/imports/inputcontext/inputcontext.pro38
-rw-r--r--src/imports/inputcontext/inputcontextfilter.cpp352
-rw-r--r--src/imports/inputcontext/inputcontextfilter.h162
-rw-r--r--src/imports/inputcontext/inputcontextmodule.cpp413
-rw-r--r--src/imports/inputcontext/inputcontextmodule.h121
-rw-r--r--src/imports/inputcontext/plugin.cpp79
-rw-r--r--src/imports/inputcontext/qmldir1
-rw-r--r--src/imports/particles/V1/qdeclarativeparticles.cpp (renamed from src/imports/particles/qdeclarativeparticles.cpp)0
-rw-r--r--src/imports/particles/V1/qdeclarativeparticles_p.h (renamed from src/imports/particles/qdeclarativeparticles_p.h)0
-rw-r--r--src/imports/particles/angledvector.cpp66
-rw-r--r--src/imports/particles/angledvector.h133
-rw-r--r--src/imports/particles/attractoraffector.cpp66
-rw-r--r--src/imports/particles/attractoraffector.h120
-rw-r--r--src/imports/particles/coloredparticle.cpp540
-rw-r--r--src/imports/particles/coloredparticle.h254
-rw-r--r--src/imports/particles/deformableparticle.cpp432
-rw-r--r--src/imports/particles/deformableparticle.h202
-rw-r--r--src/imports/particles/directedvector.cpp93
-rw-r--r--src/imports/particles/directedvector.h190
-rw-r--r--src/imports/particles/driftaffector.cpp67
-rw-r--r--src/imports/particles/driftaffector.h104
-rw-r--r--src/imports/particles/ellipseextruder.cpp64
-rw-r--r--src/imports/particles/ellipseextruder.h86
-rw-r--r--src/imports/particles/eternalaffector.cpp60
-rw-r--r--src/imports/particles/eternalaffector.h88
-rw-r--r--src/imports/particles/followemitter.cpp195
-rw-r--r--src/imports/particles/followemitter.h168
-rw-r--r--src/imports/particles/frictionaffector.cpp59
-rw-r--r--src/imports/particles/frictionaffector.h86
-rw-r--r--src/imports/particles/gravitationalsingularityaffector.cpp179
-rw-r--r--src/imports/particles/gravitationalsingularityaffector.h121
-rw-r--r--src/imports/particles/gravityaffector.cpp77
-rw-r--r--src/imports/particles/gravityaffector.h106
-rw-r--r--src/imports/particles/killaffector.cpp57
-rw-r--r--src/imports/particles/killaffector.h68
-rw-r--r--src/imports/particles/lineextruder.cpp66
-rw-r--r--src/imports/particles/lineextruder.h77
-rw-r--r--src/imports/particles/main.cpp150
-rw-r--r--src/imports/particles/maskextruder.cpp91
-rw-r--r--src/imports/particles/maskextruder.h95
-rw-r--r--src/imports/particles/meanderaffector.cpp65
-rw-r--r--src/imports/particles/meanderaffector.h103
-rw-r--r--src/imports/particles/modelparticle.cpp287
-rw-r--r--src/imports/particles/modelparticle.h136
-rw-r--r--src/imports/particles/particle.cpp135
-rw-r--r--src/imports/particles/particle.h120
-rw-r--r--src/imports/particles/particleaffector.cpp115
-rw-r--r--src/imports/particles/particleaffector.h155
-rw-r--r--src/imports/particles/particleemitter.cpp149
-rw-r--r--src/imports/particles/particleemitter.h301
-rw-r--r--src/imports/particles/particleextruder.cpp78
-rw-r--r--src/imports/particles/particleextruder.h90
-rw-r--r--src/imports/particles/particles.pro102
-rw-r--r--src/imports/particles/particlesystem.cpp392
-rw-r--r--src/imports/particles/particlesystem.h219
-rw-r--r--src/imports/particles/pictureaffector.cpp97
-rw-r--r--src/imports/particles/pictureaffector.h97
-rw-r--r--src/imports/particles/pluginmain.h65
-rw-r--r--src/imports/particles/pointvector.cpp62
-rw-r--r--src/imports/particles/pointvector.h135
-rw-r--r--src/imports/particles/resetaffector.cpp78
-rw-r--r--src/imports/particles/resetaffector.h75
-rw-r--r--src/imports/particles/resources/ctfragment.shader11
-rw-r--r--src/imports/particles/resources/ctvertex.shader38
-rw-r--r--src/imports/particles/resources/defaultFadeInOut.pngbin0 -> 286 bytes
-rw-r--r--src/imports/particles/resources/deformablefragment.shader8
-rw-r--r--src/imports/particles/resources/deformablevertex.shader57
-rw-r--r--src/imports/particles/resources/identitytable.pngbin0 -> 90 bytes
-rw-r--r--src/imports/particles/resources/spritefragment.shader10
-rw-r--r--src/imports/particles/resources/spriteimagefragment.shader9
-rw-r--r--src/imports/particles/resources/spriteimagevertex.shader52
-rw-r--r--src/imports/particles/resources/spritevertex.shader77
-rw-r--r--src/imports/particles/resources/trailsfragment.shader8
-rw-r--r--src/imports/particles/resources/trailsvertex.shader37
-rw-r--r--src/imports/particles/speedlimitaffector.cpp77
-rw-r--r--src/imports/particles/speedlimitaffector.h89
-rw-r--r--src/imports/particles/spriteengine.cpp333
-rw-r--r--src/imports/particles/spriteengine.h155
-rw-r--r--src/imports/particles/spritegoalaffector.cpp100
-rw-r--r--src/imports/particles/spritegoalaffector.h104
-rw-r--r--src/imports/particles/spriteimage.cpp354
-rw-r--r--src/imports/particles/spriteimage.h114
-rw-r--r--src/imports/particles/spriteparticle.cpp450
-rw-r--r--src/imports/particles/spriteparticle.h100
-rw-r--r--src/imports/particles/spriteparticles.qrc16
-rw-r--r--src/imports/particles/spritestate.cpp53
-rw-r--r--src/imports/particles/spritestate.h193
-rw-r--r--src/imports/particles/swarmaffector.cpp114
-rw-r--r--src/imports/particles/swarmaffector.h116
-rw-r--r--src/imports/particles/toggleaffector.cpp59
-rw-r--r--src/imports/particles/toggleaffector.h102
-rw-r--r--src/imports/particles/trailsemitter.cpp194
-rw-r--r--src/imports/particles/trailsemitter.h105
-rw-r--r--src/imports/particles/turbulenceaffector.cpp159
-rw-r--r--src/imports/particles/turbulenceaffector.h125
-rw-r--r--src/imports/particles/varyingvector.cpp56
-rw-r--r--src/imports/particles/varyingvector.h72
-rw-r--r--src/imports/particles/wanderaffector.cpp110
-rw-r--r--src/imports/particles/wanderaffector.h136
-rw-r--r--src/imports/particles/zoneaffector.cpp68
-rw-r--r--src/imports/particles/zoneaffector.h159
-rw-r--r--src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp14
-rw-r--r--src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h1
-rw-r--r--tests/auto/declarative/declarative.pro24
-rw-r--r--tests/auto/declarative/examples/tst_examples.cpp42
-rw-r--r--tests/auto/declarative/geometry/geometry.pro10
-rw-r--r--tests/auto/declarative/geometry/tst_geometry.cpp181
-rw-r--r--tests/auto/declarative/node/nodes.pro10
-rw-r--r--tests/auto/declarative/node/tst_nodestest.cpp354
-rw-r--r--tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp30
-rw-r--r--tests/auto/declarative/qdeclarativedom/data/MyItem.qml4
-rw-r--r--tests/auto/declarative/qdeclarativedom/data/import/Bar.qml2
-rw-r--r--tests/auto/declarative/qdeclarativedom/data/importlib/sublib/Foo.qml2
-rw-r--r--tests/auto/declarative/qdeclarativedom/data/importlib/sublib/qmldir2
-rw-r--r--tests/auto/declarative/qdeclarativedom/data/top.qml6
-rw-r--r--tests/auto/declarative/qdeclarativedom/tst_qdeclarativedom.cpp1326
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/Scope6Nested.qml7
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/SpecialRectangleOne.qml9
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/SpecialRectangleTwo.qml9
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importFive.js3
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importFour.js9
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importOne.js13
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importPragmaLibrary.js9
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importThree.js9
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importTwo.js10
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importWithNoImports.js11
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImport.qml14
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImportPragmaLibrary.qml20
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImportScoping.qml11
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testModuleImport.js8
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testScriptImport.js11
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failFive.qml11
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failFour.qml7
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failOne.qml7
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failThree.qml8
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failTwo.qml7
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importOne.js7
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importPragmaLibrary.js11
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importWithImports.js13
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testImportPragmaLibrary.qml8
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testModuleImport.js8
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testScriptImport.js11
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/moduleApi.qml18
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/moduleApiCaching.qml12
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/moduleApiMajorVersionFail.qml10
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/moduleApiMinorVersionFail.qml10
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/moduleApiWriting.qml27
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/realToInt.qml11
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/ScarceResourceSignalComponent.qml9
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopy.qml15
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyFromJs.qml15
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.js24
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.qml18
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.js18
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.qml8
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.js14
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.qml12
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyNoBinding.qml14
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceDestroyedCopy.qml14
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunction.qml23
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunctionFail.qml23
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceSignal.qml29
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.js48
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.qml14
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestMultiple.qml16
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestPreserve.qml15
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scope.5.qml27
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/scope.6.qml10
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp45
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/testtypes.h51
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp409
-rw-r--r--tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp12
-rw-r--r--tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp8
-rw-r--r--tests/auto/declarative/qdeclarativeinfo/data/NestedComponent.qml23
-rw-r--r--tests/auto/declarative/qdeclarativeinfo/tst_qdeclarativeinfo.cpp24
-rw-r--r--tests/auto/declarative/qdeclarativeitem/data/keynavigationtest_implicit.qml68
-rw-r--r--tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp127
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/data/wrongType.17.errors.txt1
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/data/wrongType.17.qml5
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp1
-rw-r--r--tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp8
-rw-r--r--tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp15
-rw-r--r--tests/auto/declarative/qdeclarativemoduleplugin/data/implicit1/qmldir2
-rw-r--r--tests/auto/declarative/qdeclarativemoduleplugin/data/implicit1/temptest.qml14
-rw-r--r--tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/Test.qml (renamed from tests/auto/declarative/qdeclarativedom/data/MyComponent.qml)1
-rw-r--r--tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/qmldir3
-rw-r--r--tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/temptest2.qml8
-rw-r--r--tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.cpp49
-rw-r--r--tests/auto/declarative/qdeclarativeparticles/tst_qdeclarativeparticles.cpp8
-rw-r--r--tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp3
-rw-r--r--tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp9
-rw-r--r--tests/auto/declarative/qdeclarativepositioners/tst_qdeclarativepositioners.cpp14
-rw-r--r--tests/auto/declarative/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp4
-rw-r--r--tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp110
-rw-r--r--tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp8
-rw-r--r--tests/auto/declarative/qdeclarativev4/data/doubleBoolJump.qml18
-rw-r--r--tests/auto/declarative/qdeclarativev4/data/fetchException.qml6
-rw-r--r--tests/auto/declarative/qdeclarativev4/data/logicalOr.2.qml6
-rw-r--r--tests/auto/declarative/qdeclarativev4/data/logicalOr.qml6
-rw-r--r--tests/auto/declarative/qdeclarativev4/data/nestedObjectAccess.qml5
-rw-r--r--tests/auto/declarative/qdeclarativev4/data/nullQObject.qml7
-rw-r--r--tests/auto/declarative/qdeclarativev4/data/qrealToIntRounding.qml10
-rw-r--r--tests/auto/declarative/qdeclarativev4/data/subscriptionsInConditionalExpressions.qml11
-rw-r--r--tests/auto/declarative/qdeclarativev4/data/unaryMinus.qml18
-rw-r--r--tests/auto/declarative/qdeclarativev4/data/unnecessaryReeval.qml7
-rw-r--r--tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro18
-rw-r--r--tests/auto/declarative/qdeclarativev4/testtypes.cpp49
-rw-r--r--tests/auto/declarative/qdeclarativev4/testtypes.h83
-rw-r--r--tests/auto/declarative/qdeclarativev4/tst_qdeclarativev4.cpp226
-rw-r--r--tests/auto/declarative/qdeclarativeview/tst_qdeclarativeview.cpp2
-rw-r--r--tests/auto/declarative/qdeclarativexmlhttprequest/tst_qdeclarativexmlhttprequest.cpp2
-rw-r--r--tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp22
-rw-r--r--tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.0.pngbin263 -> 343 bytes
-rw-r--r--tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.1.pngbin280 -> 349 bytes
-rw-r--r--tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.2.pngbin270 -> 345 bytes
-rw-r--r--tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.3.pngbin280 -> 349 bytes
-rw-r--r--tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.4.pngbin280 -> 353 bytes
-rw-r--r--tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.5.pngbin283 -> 351 bytes
-rw-r--r--tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.6.pngbin281 -> 349 bytes
-rw-r--r--tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.qml784
-rw-r--r--tests/auto/declarative/qmlvisual/qdeclarativepositioners/dynamic.qml13
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/colors.gifbin0 -> 505 bytes
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/colors.qml5
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/hearts.gifbin0 -> 6524 bytes
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/hearts.qml6
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/qmldir1
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/qtbug-16520.qml17
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/stickman.gifbin0 -> 164923 bytes
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/stickman.qml5
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/stickmanerror1.qml6
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/stickmanpause.qml7
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/stickmanscaled.qml7
-rw-r--r--tests/auto/declarative/qsganimatedimage/data/stickmanstopped.qml6
-rw-r--r--tests/auto/declarative/qsganimatedimage/qsganimatedimage.pro16
-rw-r--r--tests/auto/declarative/qsganimatedimage/tst_qsganimatedimage.cpp387
-rw-r--r--tests/auto/declarative/qsgborderimage/data/colors-round-remote.sci7
-rw-r--r--tests/auto/declarative/qsgborderimage/data/colors-round.sci7
-rw-r--r--tests/auto/declarative/qsgborderimage/data/colors.pngbin0 -> 1655 bytes
-rw-r--r--tests/auto/declarative/qsgborderimage/data/heart200.pngbin0 -> 7943 bytes
-rw-r--r--tests/auto/declarative/qsgborderimage/data/invalid.sci7
-rw-r--r--tests/auto/declarative/qsgborderimage/qsgborderimage.pro17
-rw-r--r--tests/auto/declarative/qsgborderimage/tst_qsgborderimage.cpp426
-rw-r--r--tests/auto/declarative/qsgcanvas/qsgcanvas.pro7
-rw-r--r--tests/auto/declarative/qsgcanvas/tst_qsgcanvas.cpp437
-rw-r--r--tests/auto/declarative/qsgflickable/data/disabledcontent.qml8
-rw-r--r--tests/auto/declarative/qsgflickable/data/flickable01.qml4
-rw-r--r--tests/auto/declarative/qsgflickable/data/flickable02.qml14
-rw-r--r--tests/auto/declarative/qsgflickable/data/flickable03.qml14
-rw-r--r--tests/auto/declarative/qsgflickable/data/flickable04.qml22
-rw-r--r--tests/auto/declarative/qsgflickable/data/flickableqgraphicswidget.qml7
-rw-r--r--tests/auto/declarative/qsgflickable/data/nestedPressDelay.qml33
-rw-r--r--tests/auto/declarative/qsgflickable/data/resize.qml27
-rw-r--r--tests/auto/declarative/qsgflickable/data/wheel.qml25
-rw-r--r--tests/auto/declarative/qsgflickable/qsgflickable.pro16
-rw-r--r--tests/auto/declarative/qsgflickable/tst_qsgflickable.cpp450
-rw-r--r--tests/auto/declarative/qsgflipable/data/crash.qml9
-rw-r--r--tests/auto/declarative/qsgflipable/data/flipable-abort.qml10
-rw-r--r--tests/auto/declarative/qsgflipable/data/test-flipable.qml9
-rw-r--r--tests/auto/declarative/qsgflipable/qsgflipable.pro16
-rw-r--r--tests/auto/declarative/qsgflipable/tst_qsgflipable.cpp143
-rw-r--r--tests/auto/declarative/qsgfocusscope/data/chain.qml28
-rw-r--r--tests/auto/declarative/qsgfocusscope/data/forceActiveFocus.qml26
-rw-r--r--tests/auto/declarative/qsgfocusscope/data/forcefocus.qml81
-rw-r--r--tests/auto/declarative/qsgfocusscope/data/qtBug13380.qml24
-rw-r--r--tests/auto/declarative/qsgfocusscope/data/signalEmission.qml33
-rw-r--r--tests/auto/declarative/qsgfocusscope/data/test.qml77
-rw-r--r--tests/auto/declarative/qsgfocusscope/data/test2.qml39
-rw-r--r--tests/auto/declarative/qsgfocusscope/data/test3.qml52
-rw-r--r--tests/auto/declarative/qsgfocusscope/data/test4.qml76
-rw-r--r--tests/auto/declarative/qsgfocusscope/data/test5.qml84
-rw-r--r--tests/auto/declarative/qsgfocusscope/qsgfocusscope.pro13
-rw-r--r--tests/auto/declarative/qsgfocusscope/tst_qsgfocusscope.cpp540
-rw-r--r--tests/auto/declarative/qsggridview/data/attachedSignals.qml27
-rw-r--r--tests/auto/declarative/qsggridview/data/displaygrid.qml39
-rw-r--r--tests/auto/declarative/qsggridview/data/footer.qml40
-rw-r--r--tests/auto/declarative/qsggridview/data/gridview-enforcerange.qml58
-rw-r--r--tests/auto/declarative/qsggridview/data/gridview-initCurrent.qml52
-rw-r--r--tests/auto/declarative/qsggridview/data/gridview-noCurrent.qml52
-rw-r--r--tests/auto/declarative/qsggridview/data/gridview1.qml65
-rw-r--r--tests/auto/declarative/qsggridview/data/gridview2.qml26
-rw-r--r--tests/auto/declarative/qsggridview/data/gridview3.qml6
-rw-r--r--tests/auto/declarative/qsggridview/data/header.qml40
-rw-r--r--tests/auto/declarative/qsggridview/data/manual-highlight.qml48
-rw-r--r--tests/auto/declarative/qsggridview/data/mirroring.qml43
-rw-r--r--tests/auto/declarative/qsggridview/data/propertychangestest.qml69
-rw-r--r--tests/auto/declarative/qsggridview/data/setindex.qml29
-rw-r--r--tests/auto/declarative/qsggridview/qsggridview.pro (renamed from tests/auto/declarative/qdeclarativedom/qdeclarativedom.pro)2
-rw-r--r--tests/auto/declarative/qsggridview/tst_qsggridview.cpp2171
-rw-r--r--tests/auto/declarative/qsgimage/data/aspectratio.qml6
-rw-r--r--tests/auto/declarative/qsgimage/data/big.jpegbin0 -> 1700081 bytes
-rw-r--r--tests/auto/declarative/qsgimage/data/big256.pngbin0 -> 3566 bytes
-rw-r--r--tests/auto/declarative/qsgimage/data/colors.pngbin0 -> 1655 bytes
-rw-r--r--tests/auto/declarative/qsgimage/data/colors1.pngbin0 -> 1655 bytes
-rw-r--r--tests/auto/declarative/qsgimage/data/green.pngbin0 -> 314 bytes
-rw-r--r--tests/auto/declarative/qsgimage/data/heart-win32.pngbin0 -> 12621 bytes
-rw-r--r--tests/auto/declarative/qsgimage/data/heart.pngbin0 -> 12577 bytes
-rw-r--r--tests/auto/declarative/qsgimage/data/heart.svg55
-rw-r--r--tests/auto/declarative/qsgimage/data/heart200-win32.pngbin0 -> 8062 bytes
-rw-r--r--tests/auto/declarative/qsgimage/data/heart200.pngbin0 -> 8063 bytes
-rw-r--r--tests/auto/declarative/qsgimage/data/qtbug_16389.qml30
-rw-r--r--tests/auto/declarative/qsgimage/data/rect.pngbin0 -> 171 bytes
-rw-r--r--tests/auto/declarative/qsgimage/data/tiling.qml16
-rw-r--r--tests/auto/declarative/qsgimage/qsgimage.pro17
-rw-r--r--tests/auto/declarative/qsgimage/tst_qsgimage.cpp776
-rw-r--r--tests/auto/declarative/qsgitem/qsgitem.pro7
-rw-r--r--tests/auto/declarative/qsgitem/tst_qsgitem.cpp787
-rw-r--r--tests/auto/declarative/qsgitem2/data/childrenProperty.qml14
-rw-r--r--tests/auto/declarative/qsgitem2/data/childrenRect.qml27
-rw-r--r--tests/auto/declarative/qsgitem2/data/childrenRectBug.qml23
-rw-r--r--tests/auto/declarative/qsgitem2/data/childrenRectBug2.qml53
-rw-r--r--tests/auto/declarative/qsgitem2/data/childrenRectBug3.qml15
-rw-r--r--tests/auto/declarative/qsgitem2/data/implicitsize.qml19
-rw-r--r--tests/auto/declarative/qsgitem2/data/keynavigationtest.qml87
-rw-r--r--tests/auto/declarative/qsgitem2/data/keynavigationtest_implicit.qml68
-rw-r--r--tests/auto/declarative/qsgitem2/data/keyspriority.qml9
-rw-r--r--tests/auto/declarative/qsgitem2/data/keystest.qml24
-rw-r--r--tests/auto/declarative/qsgitem2/data/layoutmirroring.qml54
-rw-r--r--tests/auto/declarative/qsgitem2/data/mapCoordinates.qml43
-rw-r--r--tests/auto/declarative/qsgitem2/data/mouseFocus.qml20
-rw-r--r--tests/auto/declarative/qsgitem2/data/propertychanges.qml10
-rw-r--r--tests/auto/declarative/qsgitem2/data/qtbug_16871.qml5
-rw-r--r--tests/auto/declarative/qsgitem2/data/resourcesProperty.qml21
-rw-r--r--tests/auto/declarative/qsgitem2/data/transformCrash.qml13
-rw-r--r--tests/auto/declarative/qsgitem2/qsgitem.pro16
-rw-r--r--tests/auto/declarative/qsgitem2/tst_qsgitem.cpp1322
-rw-r--r--tests/auto/declarative/qsglistview/data/attachedSignals.qml24
-rw-r--r--tests/auto/declarative/qsglistview/data/displaylist.qml50
-rw-r--r--tests/auto/declarative/qsglistview/data/footer.qml38
-rw-r--r--tests/auto/declarative/qsglistview/data/header.qml38
-rw-r--r--tests/auto/declarative/qsglistview/data/header1.qml33
-rw-r--r--tests/auto/declarative/qsglistview/data/headerfooter.qml26
-rw-r--r--tests/auto/declarative/qsglistview/data/itemlist.qml43
-rw-r--r--tests/auto/declarative/qsglistview/data/listview-enforcerange.qml55
-rw-r--r--tests/auto/declarative/qsglistview/data/listview-initCurrent.qml51
-rw-r--r--tests/auto/declarative/qsglistview/data/listview-noCurrent.qml50
-rw-r--r--tests/auto/declarative/qsglistview/data/listview-sections.qml64
-rw-r--r--tests/auto/declarative/qsglistview/data/listview-sections_delegate.qml69
-rw-r--r--tests/auto/declarative/qsglistview/data/listviewtest.qml132
-rw-r--r--tests/auto/declarative/qsglistview/data/manual-highlight.qml47
-rw-r--r--tests/auto/declarative/qsglistview/data/propertychangestest.qml71
-rw-r--r--tests/auto/declarative/qsglistview/data/qtbug14821.qml31
-rw-r--r--tests/auto/declarative/qsglistview/data/qtbug16037.qml37
-rw-r--r--tests/auto/declarative/qsglistview/data/rightToLeft.qml42
-rw-r--r--tests/auto/declarative/qsglistview/data/sizelessthan1.qml26
-rw-r--r--tests/auto/declarative/qsglistview/data/strictlyenforcerange.qml29
-rw-r--r--tests/auto/declarative/qsglistview/incrementalmodel.cpp89
-rw-r--r--tests/auto/declarative/qsglistview/incrementalmodel.h68
-rw-r--r--tests/auto/declarative/qsglistview/qsglistview.pro16
-rw-r--r--tests/auto/declarative/qsglistview/tst_qsglistview.cpp2698
-rw-r--r--tests/auto/declarative/qsgloader/data/AnchoredLoader.qml14
-rw-r--r--tests/auto/declarative/qsgloader/data/BlueRect.qml8
-rw-r--r--tests/auto/declarative/qsgloader/data/CreationContextLoader.qml15
-rw-r--r--tests/auto/declarative/qsgloader/data/GraphicsWidget250x250.qml5
-rw-r--r--tests/auto/declarative/qsgloader/data/GreenRect.qml7
-rw-r--r--tests/auto/declarative/qsgloader/data/NoResize.qml8
-rw-r--r--tests/auto/declarative/qsgloader/data/NoResizeGraphicsWidget.qml9
-rw-r--r--tests/auto/declarative/qsgloader/data/QTBUG_16928.qml23
-rw-r--r--tests/auto/declarative/qsgloader/data/QTBUG_17114.qml18
-rw-r--r--tests/auto/declarative/qsgloader/data/Rect120x60.qml6
-rw-r--r--tests/auto/declarative/qsgloader/data/SetSourceComponent.qml9
-rw-r--r--tests/auto/declarative/qsgloader/data/SizeGraphicsWidgetToLoader.qml7
-rw-r--r--tests/auto/declarative/qsgloader/data/SizeLoaderToGraphicsWidget.qml5
-rw-r--r--tests/auto/declarative/qsgloader/data/SizeToItem.qml5
-rw-r--r--tests/auto/declarative/qsgloader/data/SizeToLoader.qml6
-rw-r--r--tests/auto/declarative/qsgloader/data/VmeError.qml7
-rw-r--r--tests/auto/declarative/qsgloader/data/crash.qml14
-rw-r--r--tests/auto/declarative/qsgloader/data/creationContext.qml8
-rw-r--r--tests/auto/declarative/qsgloader/data/differentorigin.qml3
-rw-r--r--tests/auto/declarative/qsgloader/data/implicitSize.qml28
-rw-r--r--tests/auto/declarative/qsgloader/data/nonItem.qml5
-rw-r--r--tests/auto/declarative/qsgloader/data/qmldir1
-rw-r--r--tests/auto/declarative/qsgloader/data/sameorigin-load.qml3
-rw-r--r--tests/auto/declarative/qsgloader/data/sameorigin.qml3
-rw-r--r--tests/auto/declarative/qsgloader/data/vmeErrors.qml6
-rw-r--r--tests/auto/declarative/qsgloader/qsgloader.pro19
-rw-r--r--tests/auto/declarative/qsgloader/tst_qsgloader.cpp559
-rw-r--r--tests/auto/declarative/qsgmousearea/data/clickThrough.qml23
-rw-r--r--tests/auto/declarative/qsgmousearea/data/clickThrough2.qml32
-rw-r--r--tests/auto/declarative/qsgmousearea/data/clickandhold.qml13
-rw-r--r--tests/auto/declarative/qsgmousearea/data/clicktwice.qml16
-rw-r--r--tests/auto/declarative/qsgmousearea/data/doubleclick.qml16
-rw-r--r--tests/auto/declarative/qsgmousearea/data/dragging.qml28
-rw-r--r--tests/auto/declarative/qsgmousearea/data/dragproperties.qml28
-rw-r--r--tests/auto/declarative/qsgmousearea/data/dragreset.qml28
-rw-r--r--tests/auto/declarative/qsgmousearea/data/hoverPosition.qml17
-rw-r--r--tests/auto/declarative/qsgmousearea/data/pressedOrdering.qml28
-rw-r--r--tests/auto/declarative/qsgmousearea/data/preventstealing.qml24
-rw-r--r--tests/auto/declarative/qsgmousearea/data/rejectEvent.qml28
-rw-r--r--tests/auto/declarative/qsgmousearea/data/updateMousePosOnClick.qml20
-rw-r--r--tests/auto/declarative/qsgmousearea/data/updateMousePosOnResize.qml38
-rw-r--r--tests/auto/declarative/qsgmousearea/qsgmousearea.pro17
-rw-r--r--tests/auto/declarative/qsgmousearea/tst_qsgmousearea.cpp705
-rw-r--r--tests/auto/declarative/qsgpathview/data/closedPath.qml24
-rw-r--r--tests/auto/declarative/qsgpathview/data/datamodel.qml37
-rw-r--r--tests/auto/declarative/qsgpathview/data/displaypath.qml59
-rw-r--r--tests/auto/declarative/qsgpathview/data/dragpath.qml19
-rw-r--r--tests/auto/declarative/qsgpathview/data/emptymodel.qml5
-rw-r--r--tests/auto/declarative/qsgpathview/data/openPath.qml10
-rw-r--r--tests/auto/declarative/qsgpathview/data/pathUpdate.qml18
-rw-r--r--tests/auto/declarative/qsgpathview/data/pathUpdateOnStartChanged.qml38
-rw-r--r--tests/auto/declarative/qsgpathview/data/pathtest.qml14
-rw-r--r--tests/auto/declarative/qsgpathview/data/pathview0.qml83
-rw-r--r--tests/auto/declarative/qsgpathview/data/pathview1.qml4
-rw-r--r--tests/auto/declarative/qsgpathview/data/pathview2.qml57
-rw-r--r--tests/auto/declarative/qsgpathview/data/pathview3.qml59
-rw-r--r--tests/auto/declarative/qsgpathview/data/pathview_package.qml88
-rw-r--r--tests/auto/declarative/qsgpathview/data/propertychanges.qml116
-rw-r--r--tests/auto/declarative/qsgpathview/data/treemodel.qml19
-rw-r--r--tests/auto/declarative/qsgpathview/data/undefinedpath.qml17
-rw-r--r--tests/auto/declarative/qsgpathview/data/vdm.qml28
-rw-r--r--tests/auto/declarative/qsgpathview/qsgpathview.pro16
-rw-r--r--tests/auto/declarative/qsgpathview/tst_qsgpathview.cpp1058
-rw-r--r--tests/auto/declarative/qsgpincharea/data/pinchproperties.qml46
-rw-r--r--tests/auto/declarative/qsgpincharea/qsgpincharea.pro16
-rw-r--r--tests/auto/declarative/qsgpincharea/tst_qsgpincharea.cpp311
-rw-r--r--tests/auto/declarative/qsgpositioners/data/flow-testimplicitsize.qml19
-rw-r--r--tests/auto/declarative/qsgpositioners/data/flowtest-toptobottom.qml44
-rw-r--r--tests/auto/declarative/qsgpositioners/data/flowtest.qml43
-rw-r--r--tests/auto/declarative/qsgpositioners/data/grid-animated.qml64
-rw-r--r--tests/auto/declarative/qsgpositioners/data/grid-spacing.qml41
-rw-r--r--tests/auto/declarative/qsgpositioners/data/grid-toptobottom.qml41
-rw-r--r--tests/auto/declarative/qsgpositioners/data/gridtest.qml42
-rw-r--r--tests/auto/declarative/qsgpositioners/data/gridzerocolumns.qml40
-rw-r--r--tests/auto/declarative/qsgpositioners/data/horizontal-animated.qml44
-rw-r--r--tests/auto/declarative/qsgpositioners/data/horizontal-spacing.qml31
-rw-r--r--tests/auto/declarative/qsgpositioners/data/horizontal.qml29
-rw-r--r--tests/auto/declarative/qsgpositioners/data/propertychangestest.qml39
-rw-r--r--tests/auto/declarative/qsgpositioners/data/repeatertest.qml38
-rw-r--r--tests/auto/declarative/qsgpositioners/data/vertical-animated.qml41
-rw-r--r--tests/auto/declarative/qsgpositioners/data/vertical-spacing.qml28
-rw-r--r--tests/auto/declarative/qsgpositioners/data/vertical.qml27
-rw-r--r--tests/auto/declarative/qsgpositioners/qsgpositioners.pro15
-rw-r--r--tests/auto/declarative/qsgpositioners/tst_qsgpositioners.cpp1268
-rw-r--r--tests/auto/declarative/qsgrepeater/data/intmodel.qml29
-rw-r--r--tests/auto/declarative/qsgrepeater/data/itemlist.qml68
-rw-r--r--tests/auto/declarative/qsgrepeater/data/modelChanged.qml26
-rw-r--r--tests/auto/declarative/qsgrepeater/data/objlist.qml21
-rw-r--r--tests/auto/declarative/qsgrepeater/data/properties.qml11
-rw-r--r--tests/auto/declarative/qsgrepeater/data/repeater1.qml28
-rw-r--r--tests/auto/declarative/qsgrepeater/data/repeater2.qml36
-rw-r--r--tests/auto/declarative/qsgrepeater/qsgrepeater.pro15
-rw-r--r--tests/auto/declarative/qsgrepeater/tst_qsgrepeater.cpp697
-rw-r--r--tests/auto/declarative/qsgtext/data/alignments.qml41
-rw-r--r--tests/auto/declarative/qsgtext/data/alignments_cb.pngbin0 -> 496 bytes
-rw-r--r--tests/auto/declarative/qsgtext/data/alignments_cc.pngbin0 -> 556 bytes
-rw-r--r--tests/auto/declarative/qsgtext/data/alignments_ct.pngbin0 -> 533 bytes
-rw-r--r--tests/auto/declarative/qsgtext/data/alignments_lb.pngbin0 -> 496 bytes
-rw-r--r--tests/auto/declarative/qsgtext/data/alignments_lc.pngbin0 -> 535 bytes
-rw-r--r--tests/auto/declarative/qsgtext/data/alignments_lt.pngbin0 -> 514 bytes
-rw-r--r--tests/auto/declarative/qsgtext/data/alignments_rb.pngbin0 -> 505 bytes
-rw-r--r--tests/auto/declarative/qsgtext/data/alignments_rc.pngbin0 -> 559 bytes
-rw-r--r--tests/auto/declarative/qsgtext/data/alignments_rt.pngbin0 -> 539 bytes
-rw-r--r--tests/auto/declarative/qsgtext/data/embeddedImagesLocal.qml5
-rw-r--r--tests/auto/declarative/qsgtext/data/embeddedImagesLocalError.qml5
-rw-r--r--tests/auto/declarative/qsgtext/data/embeddedImagesRemote.qml5
-rw-r--r--tests/auto/declarative/qsgtext/data/embeddedImagesRemoteError.qml5
-rw-r--r--tests/auto/declarative/qsgtext/data/horizontalAlignment_RightToLeft.qml23
-rw-r--r--tests/auto/declarative/qsgtext/data/http/exists.pngbin0 -> 2738 bytes
-rw-r--r--tests/auto/declarative/qsgtext/data/lineCount.qml15
-rw-r--r--tests/auto/declarative/qsgtext/data/lineHeight.qml15
-rw-r--r--tests/auto/declarative/qsgtext/data/qtbug_14734.qml10
-rw-r--r--tests/auto/declarative/qsgtext/data/rotated.qml18
-rw-r--r--tests/auto/declarative/qsgtext/qsgtext.pro21
-rw-r--r--tests/auto/declarative/qsgtext/tst_qsgtext.cpp1432
-rw-r--r--tests/auto/declarative/qsgtextedit/data/CursorRect.qml8
-rw-r--r--tests/auto/declarative/qsgtextedit/data/alignments.qml41
-rw-r--r--tests/auto/declarative/qsgtextedit/data/alignments_cb.pngbin0 -> 496 bytes
-rw-r--r--tests/auto/declarative/qsgtextedit/data/alignments_cc.pngbin0 -> 556 bytes
-rw-r--r--tests/auto/declarative/qsgtextedit/data/alignments_ct.pngbin0 -> 533 bytes
-rw-r--r--tests/auto/declarative/qsgtextedit/data/alignments_lb.pngbin0 -> 496 bytes
-rw-r--r--tests/auto/declarative/qsgtextedit/data/alignments_lc.pngbin0 -> 535 bytes
-rw-r--r--tests/auto/declarative/qsgtextedit/data/alignments_lt.pngbin0 -> 514 bytes
-rw-r--r--tests/auto/declarative/qsgtextedit/data/alignments_rb.pngbin0 -> 505 bytes
-rw-r--r--tests/auto/declarative/qsgtextedit/data/alignments_rc.pngbin0 -> 559 bytes
-rw-r--r--tests/auto/declarative/qsgtextedit/data/alignments_rt.pngbin0 -> 539 bytes
-rw-r--r--tests/auto/declarative/qsgtextedit/data/cursorTest.qml8
-rw-r--r--tests/auto/declarative/qsgtextedit/data/cursorVisible.qml6
-rw-r--r--tests/auto/declarative/qsgtextedit/data/geometrySignals.qml12
-rw-r--r--tests/auto/declarative/qsgtextedit/data/horizontalAlignment_RightToLeft.qml23
-rw-r--r--tests/auto/declarative/qsgtextedit/data/http/ErrItem.qml7
-rw-r--r--tests/auto/declarative/qsgtextedit/data/http/NormItem.qml6
-rw-r--r--tests/auto/declarative/qsgtextedit/data/http/cursorHttpTest.qml22
-rw-r--r--tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestFail1.qml18
-rw-r--r--tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestFail2.qml18
-rw-r--r--tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestPass.qml18
-rw-r--r--tests/auto/declarative/qsgtextedit/data/http/qmldir4
-rw-r--r--tests/auto/declarative/qsgtextedit/data/httpfail/FailItem.qml5
-rw-r--r--tests/auto/declarative/qsgtextedit/data/httpslow/WaitItem.qml5
-rw-r--r--tests/auto/declarative/qsgtextedit/data/inputContext.qml7
-rw-r--r--tests/auto/declarative/qsgtextedit/data/inputMethodEvent.qml5
-rw-r--r--tests/auto/declarative/qsgtextedit/data/inputmethodhints.qml6
-rw-r--r--tests/auto/declarative/qsgtextedit/data/mouseselection_default.qml7
-rw-r--r--tests/auto/declarative/qsgtextedit/data/mouseselection_false.qml7
-rw-r--r--tests/auto/declarative/qsgtextedit/data/mouseselection_false_words.qml7
-rw-r--r--tests/auto/declarative/qsgtextedit/data/mouseselection_true.qml7
-rw-r--r--tests/auto/declarative/qsgtextedit/data/mouseselection_true_words.qml7
-rw-r--r--tests/auto/declarative/qsgtextedit/data/mouseselectionmode_characters.qml8
-rw-r--r--tests/auto/declarative/qsgtextedit/data/mouseselectionmode_default.qml7
-rw-r--r--tests/auto/declarative/qsgtextedit/data/mouseselectionmode_words.qml8
-rw-r--r--tests/auto/declarative/qsgtextedit/data/navigation.qml24
-rw-r--r--tests/auto/declarative/qsgtextedit/data/openInputPanel.qml6
-rw-r--r--tests/auto/declarative/qsgtextedit/data/positionAt.qml9
-rw-r--r--tests/auto/declarative/qsgtextedit/data/readOnly.qml12
-rw-r--r--tests/auto/declarative/qsgtextedit/qsgtextedit.pro14
-rw-r--r--tests/auto/declarative/qsgtextedit/tst_qsgtextedit.cpp2388
-rw-r--r--tests/auto/declarative/qsgtextinput/data/cursorTest.qml8
-rw-r--r--tests/auto/declarative/qsgtextinput/data/cursorVisible.qml6
-rw-r--r--tests/auto/declarative/qsgtextinput/data/echoMode.qml11
-rw-r--r--tests/auto/declarative/qsgtextinput/data/geometrySignals.qml12
-rw-r--r--tests/auto/declarative/qsgtextinput/data/halign_center.pngbin0 -> 293 bytes
-rw-r--r--tests/auto/declarative/qsgtextinput/data/halign_left.pngbin0 -> 291 bytes
-rw-r--r--tests/auto/declarative/qsgtextinput/data/halign_right.pngbin0 -> 292 bytes
-rw-r--r--tests/auto/declarative/qsgtextinput/data/horizontalAlignment.qml22
-rw-r--r--tests/auto/declarative/qsgtextinput/data/horizontalAlignment_RightToLeft.qml23
-rw-r--r--tests/auto/declarative/qsgtextinput/data/inputContext.qml8
-rw-r--r--tests/auto/declarative/qsgtextinput/data/inputMethodEvent.qml5
-rw-r--r--tests/auto/declarative/qsgtextinput/data/inputmethods.qml7
-rw-r--r--tests/auto/declarative/qsgtextinput/data/masks.qml7
-rw-r--r--tests/auto/declarative/qsgtextinput/data/maxLength.qml7
-rw-r--r--tests/auto/declarative/qsgtextinput/data/mouseselection_true.qml7
-rw-r--r--tests/auto/declarative/qsgtextinput/data/mouseselectionmode_characters.qml8
-rw-r--r--tests/auto/declarative/qsgtextinput/data/mouseselectionmode_default.qml7
-rw-r--r--tests/auto/declarative/qsgtextinput/data/mouseselectionmode_words.qml8
-rw-r--r--tests/auto/declarative/qsgtextinput/data/navigation.qml24
-rw-r--r--tests/auto/declarative/qsgtextinput/data/openInputPanel.qml6
-rw-r--r--tests/auto/declarative/qsgtextinput/data/positionAt.qml8
-rw-r--r--tests/auto/declarative/qsgtextinput/data/preeditAutoScroll.qml7
-rw-r--r--tests/auto/declarative/qsgtextinput/data/readOnly.qml12
-rw-r--r--tests/auto/declarative/qsgtextinput/data/validators.qml22
-rw-r--r--tests/auto/declarative/qsgtextinput/qsgtextinput.pro14
-rw-r--r--tests/auto/declarative/qsgtextinput/tst_qsgtextinput.cpp2471
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/datalist.qml18
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/modelproperties.qml19
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/modelproperties2.qml19
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/objectlist.qml19
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/singlerole1.qml10
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/singlerole2.qml10
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/visualdatamodel.qml11
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/qsgvisualdatamodel.pro16
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp531
-rw-r--r--tests/benchmarks/declarative/declarative.pro1
-rw-r--r--tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicFour.qml78
-rw-r--r--tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicOne.qml56
-rw-r--r--tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicThree.qml61
-rw-r--r--tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicTwo.qml68
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/Mlbsi.qml49
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/Mldsi.qml49
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/Mlsi.qml49
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/ModuleBm.qml49
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/Msbsi.qml49
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/Msdsi.qml49
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/Mssi.qml49
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/PragmaBm.qml55
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/PragmaModuleBm.qml51
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/Slsi.qml49
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/Sssi.qml49
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi.js133
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi1.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi10.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi11.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi12.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi13.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi14.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi15.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi2.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi3.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi4.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi5.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi6.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi7.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi8.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlbsi9.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi.js105
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi1.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi10.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi11.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi12.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi13.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi14.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi15.js104
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi2.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi3.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi4.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi5.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi6.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi7.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi8.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mldsi9.js107
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mlsi.js138
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/moduleBm.js109
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi.js79
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi1.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi10.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi11.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi12.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi13.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi14.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi15.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi2.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi3.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi4.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi5.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi6.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi7.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi8.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msbsi9.js53
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi.js51
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi1.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi10.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi11.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi12.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi13.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi14.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi15.js49
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi2.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi3.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi4.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi5.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi6.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi7.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi8.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/msdsi9.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/mssi.js84
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/pragmaBmOne.js50
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/pragmaBmTwo.js50
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/pragmaLib.js119
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/pragmaModuleBm.js57
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/slsi.js108
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsImports/sssi.js52
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsTargets/JsOne.qml61
-rw-r--r--tests/benchmarks/declarative/holistic/data/jsTargets/JsTwo.qml118
-rw-r--r--tests/benchmarks/declarative/holistic/data/largeTargets/gridview-example.qml91
-rw-r--r--tests/benchmarks/declarative/holistic/data/largeTargets/layoutdirection.qml151
-rw-r--r--tests/benchmarks/declarative/holistic/data/largeTargets/mousearea-example.qml112
-rw-r--r--tests/benchmarks/declarative/holistic/data/resolutionTargets/ResolveOne.qml111
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/CppToJs.qml52
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/CppToQml.qml48
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppEight.qml54
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppEleven.qml57
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppFive.qml54
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppFour.qml55
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppNine.qml56
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppOne.qml55
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppSeven.qml54
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppSix.qml54
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppTen.qml56
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppThree.qml55
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppTwo.qml55
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/ScarceOne.qml57
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/ScarceTwo.qml52
-rw-r--r--tests/benchmarks/declarative/holistic/data/scopeSwitching/cppToJs.js49
-rw-r--r--tests/benchmarks/declarative/holistic/data/smallTargets/SmallFour.qml49
-rw-r--r--tests/benchmarks/declarative/holistic/data/smallTargets/SmallOne.qml51
-rw-r--r--tests/benchmarks/declarative/holistic/data/smallTargets/SmallThree.qml51
-rw-r--r--tests/benchmarks/declarative/holistic/data/smallTargets/SmallTwo.qml51
-rw-r--r--tests/benchmarks/declarative/holistic/holistic.pro19
-rw-r--r--tests/benchmarks/declarative/holistic/testtypes.cpp98
-rw-r--r--tests/benchmarks/declarative/holistic/testtypes.h355
-rw-r--r--tests/benchmarks/declarative/holistic/tst_holistic.cpp612
-rw-r--r--tests/benchmarks/declarative/script/data/enums.qml51
-rw-r--r--tests/benchmarks/declarative/script/data/namespacedEnums.qml52
-rw-r--r--tests/benchmarks/declarative/script/data/script.js1
-rw-r--r--tests/benchmarks/declarative/script/data/script2.js2
-rw-r--r--tests/benchmarks/declarative/script/data/scriptCall.qml54
-rw-r--r--tests/benchmarks/declarative/script/tst_script.cpp107
-rw-r--r--tools/distfieldgen/distfieldgen.pro12
-rw-r--r--tools/distfieldgen/main.cpp262
-rw-r--r--tools/qmlplugindump/Info.plist16
-rw-r--r--tools/qmlplugindump/main.cpp597
-rw-r--r--tools/qmlplugindump/qmlplugindump.pro20
-rw-r--r--tools/qmlplugindump/qmlstreamwriter.cpp183
-rw-r--r--tools/qmlplugindump/qmlstreamwriter.h79
-rw-r--r--tools/qmlscene/main.cpp574
-rw-r--r--tools/qmlscene/qmlscene.pro20
-rw-r--r--tools/qmlviewer/main.cpp7
-rw-r--r--tools/qmlviewer/qmlruntime.cpp1
-rw-r--r--tools/tools.pro2
1061 files changed, 125729 insertions, 7477 deletions
diff --git a/demos/declarative/plasmapatrol/PlasmaPatrol.qmlproject b/demos/declarative/plasmapatrol/PlasmaPatrol.qmlproject
new file mode 100644
index 0000000000..53f5ecb8d2
--- /dev/null
+++ b/demos/declarative/plasmapatrol/PlasmaPatrol.qmlproject
@@ -0,0 +1,18 @@
+/* File generated by QtCreator */
+
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ "../exampleplugin" ]
+}
diff --git a/demos/declarative/plasmapatrol/TODO b/demos/declarative/plasmapatrol/TODO
new file mode 100644
index 0000000000..ef9d21a73d
--- /dev/null
+++ b/demos/declarative/plasmapatrol/TODO
@@ -0,0 +1,10 @@
+Realistic Tasks:
+Particle explosions on ship death.
+Better help text (both content and styled a little nicer).
+Hardpoint help showing them firing across the screen.
+Endless Demo Mode
+
+Nice-but-i-doubt-it-will-get-done Tasks:
+Particle Text for the winner.
+Particle-based buttons.
+Single player mode that is challenges (known opponents) to master the game with and earn achievements (in addition to 'skirmish').
diff --git a/demos/declarative/plasmapatrol/content/BlasterHardpoint.qml b/demos/declarative/plasmapatrol/content/BlasterHardpoint.qml
new file mode 100644
index 0000000000..8d36cdfb13
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/BlasterHardpoint.qml
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+Item {
+ id: container
+ property variant target: {"y": -90, "x":12}
+ property Item targetObj: container
+ property Item hardpoint: container
+ property ParticleSystem system
+ property int blasts: 16
+ property int bonusBlasts: 12
+ property bool show: true
+
+ width: 24
+ height: 24
+ TrailEmitter{
+ id: visualization
+ particle: "blaster"
+ system: container.system
+ emitting: show
+ anchors.fill: parent
+ shape: Ellipse{}
+ speed: DirectedVector{ targetX: width/2; targetY: width/2; magnitude: -1; proportionalMagnitude: true}
+ particleDuration: 1000
+ particlesPerSecond: 64
+
+ particleSize: 24
+ particleSizeVariation: 24
+ particleEndSize: 0
+ }
+
+ property int blastsLeft: 0
+ function fireAt(targetArg, container){
+ target = container.mapFromItem(targetArg, targetArg.width/2, targetArg.height/2);
+ targetObj = targetArg;
+ hardpoint = container;
+ blastsLeft = blasts;
+ rofTimer.repeat = true;
+ rofTimer.start();
+ }
+ Timer{
+ id: rofTimer
+ interval: 30;//Has to be greater than 1 frame or they stack up
+ running: false
+ repeat: false
+ onTriggered:{
+ if(targetObj.hp <= 0)
+ return;
+ //TODO: calculate hit and damage at target, which must be a Ship
+ var hit;
+ if(blastsLeft >= bonusBlasts)
+ hit = Math.random() > targetObj.dodge;
+ else
+ hit = false; //purely aesthetic shots, because the damage isn't that fine grained
+ if(hit == true){
+ switch(targetObj.shipType){
+ case 1: hardpoint.damageDealt += 4; break;
+ case 2: hardpoint.damageDealt += 5; break;
+ case 3: hardpoint.damageDealt += 1; break;
+ default: hardpoint.damageDealt += 100;
+ }
+ }
+ blastVector.targetX = target.x;
+ blastVector.targetY = target.y;
+ if(!hit){//TODO: Actual targetVariation
+ blastVector.targetX += (128 * Math.random() - 64);
+ blastVector.targetY += (128 * Math.random() - 64);
+ }
+ emitter.burst(1);
+ blastsLeft--;
+ if(!blastsLeft)
+ rofTimer.repeat = false;
+ }
+ }
+ TrailEmitter{
+ id: emitter
+ particle: "blaster"
+ emitting: false
+ system: container.system
+ anchors.centerIn: parent
+
+ particleDuration: 1000
+ particlesPerSecond: 16
+ maxParticles: blasts
+ particleSize: 24
+ particleEndSize:16
+ particleSizeVariation: 8
+ speed: DirectedVector{
+ id: blastVector
+ targetX: target.x; targetY: target.y; magnitude: 1.1; proportionalMagnitude: true
+ }
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/Button.qml b/demos/declarative/plasmapatrol/content/Button.qml
new file mode 100644
index 0000000000..0d810e3b75
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/Button.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+//TODO: Add particles to this component too
+Rectangle{
+ id: container
+ property alias text: txt.text
+ signal clicked
+ //color: "lightsteelblue"
+ gradient: Gradient{
+ GradientStop{ position: 0.0; color: "lightsteelblue" }
+ GradientStop{ position: 1.0; color: "steelblue" }
+ }
+ height: 64
+ radius: 16
+ width: 128
+ Text{
+ id: txt
+ anchors.centerIn: parent
+ font.pixelSize: 24
+ color: "white"
+ }
+ MouseArea{
+ anchors.fill: parent
+ onClicked: container.clicked()
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/CannonHardpoint.qml b/demos/declarative/plasmapatrol/content/CannonHardpoint.qml
new file mode 100644
index 0000000000..d9a307cc64
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/CannonHardpoint.qml
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+Item {
+ id: container
+ property variant target: {"y": -90, "x":12}
+ property ParticleSystem system
+ property bool show: true
+
+ width: 24
+ height: 24
+ TrailEmitter{
+ id: visualization
+ particle: "cannon"
+ emitting: container.show
+ system: container.system
+ anchors.centerIn: parent
+ particleDuration: 2000
+ particlesPerSecond: 1
+
+ particleSize: 4
+ particleEndSize: 0
+ }
+
+ function fireAt(targetArg, hardpoint){
+ target = container.mapFromItem(targetArg, targetArg.width/2, targetArg.height/2);
+ if(container.hp <= 0 || targetArg.hp <= 0)
+ return;
+ //TODO: calculate hit and damage at target, which must be a Ship
+ var hit = Math.random() > targetArg.dodge
+ if(hit){
+ switch(targetArg.shipType){
+ case 1: hardpoint.damageDealt += 8; break;
+ case 2: hardpoint.damageDealt += 10; break;
+ case 3: hardpoint.damageDealt += 16; break;
+ default: hardpoint.damageDealt += 1000;
+ }
+ }
+ emitter.burst(1);
+ }
+ TrailEmitter{
+ id: emitter
+ particle: "cannon"
+ emitting: false
+ system: container.system
+ anchors.centerIn: parent
+
+ particleDuration: 1000
+ particlesPerSecond: 1
+ particleSize: 8
+ particleEndSize: 4
+ speed: DirectedVector{
+ id: blastVector
+ targetX: target.x; targetY: target.y; magnitude: 1.1; proportionalMagnitude: true
+ }
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/ChoiceBox.qml b/demos/declarative/plasmapatrol/content/ChoiceBox.qml
new file mode 100644
index 0000000000..6bdc4288ee
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/ChoiceBox.qml
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+Item{
+ id: container
+ width: 360
+ height: 160
+ property ParticleSystem system
+ Ship{
+ id: nully
+ system: system
+ }
+ property Item target: nully
+ /*
+ Component.onCompleted:{
+ container.target.shipType = 1
+ container.target.gunType = 1
+ }
+ */
+ Row{
+ anchors.horizontalCenter: parent.horizontalCenter
+ height: parent.height
+ spacing: 8
+ Button{
+ width: 80
+ height: 80
+ anchors.verticalCenter: parent.verticalCenter
+ text: "Cycle\nShip"
+ onClicked: {
+ var nextVal = container.target.shipType;
+ if(nextVal == 3)
+ nextVal = 1;
+ else
+ nextVal++;
+ container.target.shipType = nextVal;
+ }
+ }
+ Item{
+ width: 128
+ height: 128
+ anchors.verticalCenter: parent.verticalCenter
+ Ship{
+ hp: 20
+ anchors.centerIn: parent
+ shipType: container.target.shipType
+ gunType: container.target.gunType
+ system: container.system
+ }
+ }
+ Button{
+ width: 80
+ height: 80
+ anchors.verticalCenter: parent.verticalCenter
+ text: "Cycle\nGun"
+ onClicked: {
+ var nextVal = container.target.gunType;
+ if(nextVal == 3)
+ nextVal = 1;
+ else
+ nextVal++;
+ container.target.gunType = nextVal;
+ }
+ }
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/Cruiser.qml b/demos/declarative/plasmapatrol/content/Cruiser.qml
new file mode 100644
index 0000000000..8b8073328e
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/Cruiser.qml
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+Item {
+ id: container
+ property int maxHP: 100
+ property int hp: maxHP
+ property real initialDodge: 0.01
+ property real dodge: initialDodge
+ onHpChanged: if(hp <= 0) target = container;
+ property ParticleSystem system//TODO: Ship abstraction
+ property Item target: container
+ property string shipParticle: "default"//Per team colors?
+ property int gunType: 0
+ width: 128
+ height: 128
+ TrailEmitter{
+ //TODO: Cooler would be an 'orbiting' affector
+ //TODO: On the subject, opacity and size should be grouped type 'overLife' if we can cram that in the particles
+ system: container.system
+ particle: container.shipParticle
+ anchors.centerIn: parent
+ width: 64
+ height: 64
+ shape: Ellipse{}
+
+ particlesPerSecond: hp > 0 ? hp * 1 + 20 : 0
+ particleDuration: 2400
+ maxParticles: (maxHP * 1 + 20)*2.4
+
+ particleSize: 48
+ particleSizeVariation: 16
+ particleEndSize: 16
+
+ speed: AngleVector{angleVariation:360; magnitudeVariation: 32}
+ }
+ TrailEmitter{
+ system: container.system
+ particle: "cruiserArmor"
+ anchors.fill: parent
+ shape: Ellipse{ fill: false }
+ emitting: hp>0
+
+ particlesPerSecond: 16
+ particleDuration: 2000
+
+ particleSize: 48
+ particleSizeVariation: 24
+
+ SpriteGoal{
+ id: destructor
+ system: container.system
+ active: container.hp <=0
+ anchors.fill: parent
+ particles: ["cruiserArmor"]
+ goalState: "death"
+// jump: true
+ onceOff: true
+ }
+ }
+
+ Timer{
+ id: fireControl
+ property int next: Math.floor(Math.random() * 3) + 1
+ interval: 800
+ running: root.readySetGo
+ repeat: true
+ onTriggered:{
+ if(next == 1){
+ gun1.fireAt(container.target);
+ next = Math.floor(Math.random() * 3) + 1;
+ }else if(next == 2){
+ gun2.fireAt(container.target);
+ next = Math.floor(Math.random() * 3) + 1;
+ }else if(next == 3){
+ gun3.fireAt(container.target);
+ next = Math.floor(Math.random() * 3) + 1;
+ }
+ }
+ }
+
+ Hardpoint{//TODO: Hardpoint abstraction
+ x: 112 - 12 - 8*2
+ y: 128 - 12 - 12*2
+ id: gun1
+ system: container.system
+ show: hp > 0
+ hardpointType: gunType
+ }
+ Hardpoint{
+ x: 64 - 12
+ y: 0 - 12 + 12*2
+ id: gun2
+ system: container.system
+ show: hp > 0
+ hardpointType: gunType
+ }
+ Hardpoint{
+ x: 16 - 12 + 8*2
+ y: 128 - 12 - 12*2
+ id: gun3
+ system: container.system
+ show: hp > 0
+ hardpointType: gunType
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/Frigate.qml b/demos/declarative/plasmapatrol/content/Frigate.qml
new file mode 100644
index 0000000000..54f629268f
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/Frigate.qml
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+Item {
+ id: container
+ property int maxHP: 100
+ property int hp: maxHP
+ property real initialDodge: 0.2
+ property real dodge: initialDodge
+ onHpChanged: if(hp <= 0) target = container;
+ property ParticleSystem system//TODO: Ship abstraction
+ property Item target: container
+ property string shipParticle: "default"//Per team colors?
+ property int gunType: 0
+ width: 128
+ height: 128
+ TrailEmitter{
+ system: container.system
+ particle: "frigateShield"
+ anchors.centerIn: parent
+ particleSize: 92
+ particlesPerSecond: 1
+ particleDuration: 4800
+ emitting: hp > 0
+ }
+ TrailEmitter{
+ system: container.system
+ particle: container.shipParticle
+ anchors.centerIn: parent
+ width: 64
+ height: 16
+ shape: Ellipse{}
+
+ particleSize: 16
+ particleSizeVariation: 8
+ particleEndSize: 8
+ particlesPerSecond: hp > 0 ? hp * 1 + 20 : 0
+ particleDuration: 1200
+ maxParticles: (maxHP * 1 + 20)*2
+ }
+ Timer{
+ id: fireControl
+ property int next: Math.floor(Math.random() * 2) + 1
+ interval: 800
+ running: root.readySetGo
+ repeat: true
+ onTriggered:{
+ if(next == 1){
+ gun1.fireAt(container.target);
+ next = Math.floor(Math.random() * 2) + 1;
+ }else if(next == 2){
+ gun2.fireAt(container.target);
+ next = Math.floor(Math.random() * 2) + 1;
+ }
+ }
+ }
+
+ Hardpoint{
+ x: 128 - 32 - 12
+ y: 64 - 12
+ id: gun1
+ system: container.system
+ show: hp > 0
+ hardpointType: gunType
+ }
+ Hardpoint{
+ x: 0 + 32 - 12
+ y: 64 - 12
+ id: gun2
+ system: container.system
+ show: hp > 0
+ hardpointType: gunType
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/Hardpoint.qml b/demos/declarative/plasmapatrol/content/Hardpoint.qml
new file mode 100644
index 0000000000..184c750a79
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/Hardpoint.qml
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+Item {
+ id: container
+ //ReflectiveProperties
+ //TransferredProperties
+ property variant target: {"y": -90, "x":12}
+ property ParticleSystem system
+ property bool show: true
+ property int hardpointType: 0 //default is pea shooter - always bad.
+
+ property Item targetObj: null
+ property int damageDealt: 0
+ onDamageDealtChanged: dealDamageTimer.start();
+ Timer{
+ id: dealDamageTimer
+ interval: 16
+ running: false
+ repeat: false
+ onTriggered: {targetObj.hp -= damageDealt; damageDealt = 0;}
+ }
+ width: 24
+ height: 24
+ function fireAt(targetArg){//Each implement own
+ if(targetArg != null){
+ hardpointLoader.item.fireAt(targetArg, container);
+ targetObj = targetArg;
+ }
+ }
+ Loader{
+ id: hardpointLoader
+ sourceComponent: {switch(hardpointType){
+ case 1: laserComponent; break;
+ case 2: blasterComponent; break;
+ case 3: cannonComponent; break;
+ default: emptyComponent;
+ }}
+ }
+ Component{
+ id: laserComponent
+ LaserHardpoint{
+ target: container.target
+ system: container.system
+ show: container.show
+ }
+ }
+ Component{
+ id: blasterComponent
+ BlasterHardpoint{
+ target: container.target
+ system: container.system
+ show: container.show
+ }
+ }
+ Component{
+ id: cannonComponent
+ CannonHardpoint{
+ target: container.target
+ system: container.system
+ show: container.show
+ }
+ }
+ Component{
+ id: emptyComponent
+ Item {
+ function fireAt(obj){
+ console.log("Firing null weapon. It hurts.");
+ }
+ }
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/HelpScreens.qml b/demos/declarative/plasmapatrol/content/HelpScreens.qml
new file mode 100644
index 0000000000..8896aeee4a
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/HelpScreens.qml
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+SequentialLoader {
+ id: hLdr
+ signal exitDesired
+ Component.onCompleted: advance();
+ ParticleSystem{ id: helpSystem }
+ PlasmaPatrolParticles{ sys: helpSystem }
+ pages: [
+ Component{Item{
+ id: story
+ Text{
+ color: "white"
+ text: "Story"
+ font.pixelSize: 48
+ }
+ /*
+ Flickable{
+ y: 60
+ width: 360
+ height: 500
+ contentHeight: txt1.height
+ contentWidth: 360//TODO: Less magic numbers?
+ */
+ Text{
+ id: txt1
+ color: "white"
+ y: 60
+ font.pixelSize: 18
+ text: "
+In a remote nebula, a race of energy beings formed and lived prosperous lives for millenia. Until the schism - when they became constantly at each other's energy-throats. War soon followed, crippling both sides, until a truce was formed. But while governments knew the desparate need for peace, the soldiers in the ion-field were still filled with rampant bloodlust. On the border, patrols are constantly engaging in minor skirmishes whenever they cross paths.
+
+You must select one such patrol unit for the border, heading into an inevitable skirmish, in Plasma Patrol: the game of energy being spaceship combat!
+ "
+ width: 360
+ wrapMode: Text.WordWrap
+ }
+ // }
+ Button{
+ x: 20
+ y: 560
+ height: 40
+ width: 120
+ text: "Next"
+ onClicked: hLdr.advance();
+ }
+ Button{
+ x: 220
+ y: 560
+ height: 40
+ width: 120
+ text: "Menu"
+ onClicked: hLdr.exitDesired();
+ }
+ }},
+ Component{Item{
+ id: ships
+ Text{
+ color: "white"
+ text: "Vessels"
+ font.pixelSize: 48
+ }
+ Column{
+ spacing: 16
+ y: 60
+ Row{
+ height: 128
+ Sloop{
+ system: helpSystem
+ }
+ Text{
+ text: "The nimble sloop"
+ color: "white"
+ font.pixelSize: 18
+ }
+ }
+ Row{
+ height: 128
+ Frigate{
+ system: helpSystem
+ }
+ Text{
+ text: "The versitile shield frigate"
+ color: "white"
+ font.pixelSize: 18
+ }
+ }
+ Row{
+ height: 128
+ Cruiser{
+ system: helpSystem
+ }
+ Text{
+ text: "The armored cruiser"
+ color: "white"
+ font.pixelSize: 18
+ }
+ }
+ }
+ Button{
+ x: 20
+ y: 560
+ height: 40
+ width: 120
+ text: "Next"
+ onClicked: hLdr.advance();
+ }
+ Button{
+ x: 220
+ y: 560
+ height: 40
+ width: 120
+ text: "Menu"
+ onClicked: hLdr.exitDesired();
+ }
+ }},
+ Component{Item{
+ id: guns
+ Text{
+ color: "white"
+ text: "Hardpoints"
+ font.pixelSize: 48
+ }
+ Column{
+ spacing: 16
+ y: 60
+ Row{
+ height: 128
+ LaserHardpoint{
+ system: helpSystem
+ }
+ Text{
+ text: "The laser hardpoint almost always hits the target, even the nimble sloop, but loses much of its potency against the frigate's shields"
+ width: 332
+ wrapMode: Text.WordWrap
+ color: "white"
+ font.pixelSize: 18
+ }
+ }
+ Row{
+ height: 128
+ BlasterHardpoint{
+ system: helpSystem
+ }
+ Text{
+ text: "The blaster passes right through the frigate's shields but loses much of its impact against the armor of the cruiser"
+ width: 332
+ wrapMode: Text.WordWrap
+ color: "white"
+ font.pixelSize: 18
+ }
+ }
+ Row{
+ height: 128
+ CannonHardpoint{
+ system: helpSystem
+ }
+ Text{
+ text: "The cannon has poor accuracy, often missing the nimble sloop, but can punch right through the armor of the cruiser"
+ width: 332
+ wrapMode: Text.WordWrap
+ color: "white"
+ font.pixelSize: 18
+ }
+ }
+ }
+ Button{
+ x: 20
+ y: 560
+ height: 40
+ width: 120
+ text: "Next"
+ onClicked: hLdr.advance();
+ }
+ Button{
+ x: 220
+ y: 560
+ height: 40
+ width: 120
+ text: "Menu"
+ onClicked: hLdr.exitDesired();
+ }
+ }},
+ Component{Item{
+ id: strategy
+ Text{
+ color: "white"
+ text: "Strategy"
+ font.pixelSize: 48
+ }
+ Flickable{
+ y: 60
+ width: 360
+ height: 500
+ contentHeight: txt1.height
+ contentWidth: 360//TODO: Less magic numbers?
+ Text{
+ id: txt1
+ color: "white"
+ font.pixelSize: 18
+ text: "
+Basic Strategy: Good luck, have fun - don't die.
+More to come after thorough playtesting.
+ "
+ width: 360
+ wrapMode: Text.WordWrap
+ }
+ }
+ Button{
+ x: 20
+ y: 560
+ height: 40
+ width: 120
+ text: "Story"
+ onClicked: {hLdr.at=0; hLdr.advance();}
+ }
+ Button{
+ x: 220
+ y: 560
+ height: 40
+ width: 120
+ text: "Menu"
+ onClicked: hLdr.exitDesired();
+ }
+ }}
+ ]
+}
diff --git a/demos/declarative/plasmapatrol/content/LaserHardpoint.qml b/demos/declarative/plasmapatrol/content/LaserHardpoint.qml
new file mode 100644
index 0000000000..d6d470a15b
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/LaserHardpoint.qml
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+Item {
+ id: container
+ property variant target: {"y": -90, "x":12}
+ property ParticleSystem system
+ property bool show: true
+
+ width: 24
+ height: 24
+ TrailEmitter{
+ id: visualization
+ particle: "laser"
+ system: container.system
+ anchors.fill: parent
+ emitting: container.show
+ shape: Ellipse{}
+ speed: DirectedVector{ targetX: width/2; targetY: width/2; magnitude: -1; proportionalMagnitude: true }
+ particleDuration: 1000
+ particlesPerSecond: 64
+
+ particleSize: 24
+ particleSizeVariation: 8
+ particleEndSize: 8
+ }
+
+ function fireAt(targetArg, hardpoint){
+ if(targetArg.hp <= 0)
+ return;
+ //TODO: calculate hit and damage at target, which must be a Ship
+ var offset = 0;
+ if(Math.random() < 0.99){
+ switch(targetArg.shipType){
+ case 1: hardpoint.damageDealt += 16; break;
+ case 2: hardpoint.damageDealt += 4; break;
+ case 3: hardpoint.damageDealt += 8; break;
+ default: hardpoint.damageDealt += 500; //Really effective against unregistered vessels
+ }
+ }else{//Misses with Lasers are really rare
+ offset = Math.random() * 100;
+ }
+ target = container.mapFromItem(targetArg, offset + targetArg.width/2, offset + targetArg.height/2);
+ emitter.pulse(0.10);
+ // console.log("Fire box: " + Math.min(container.width/2, target.x) + "," + Math.min(container.height/2, target.y) + " " + (Math.max(container.width/2, target.x) - Math.min(container.width/2, target.x)) + "," + (Math.max(container.height/2, target.y) - Math.min(container.height/2, target.y)));
+ }
+ TrailEmitter{
+ id: emitter
+ particle: "laser"
+ emitting: false
+ system: container.system
+ x: Math.min(container.width/2, target.x);
+ width: Math.max(container.width/2, target.x) - x;
+ y: Math.min(container.height/2, target.y);
+ height: Math.max(container.height/2, target.y) - y;
+ shape: Line{
+ mirrored: (emitter.y < 0 || emitter.x < 0) && !(emitter.y < 0 && emitter.x < 0 )//I just want XOR
+ }
+
+ particleDuration: 1000
+ particlesPerSecond: 8000
+ maxParticles: 800
+ particleSize: 16
+ particleEndSize: 0
+
+ speed: PointVector{xVariation: 4; yVariation: 4}
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/PlasmaPatrolParticles.qml b/demos/declarative/plasmapatrol/content/PlasmaPatrolParticles.qml
new file mode 100644
index 0000000000..7a6fcb96d0
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/PlasmaPatrolParticles.qml
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+Item{
+ property ParticleSystem sys
+ ColoredParticle{
+ system: sys
+ particles: ["default"]
+ image: "pics/blur-circle3.png"
+ color: "#003A3A3A"
+ colorVariation: 0.1
+ z: 0
+ }
+ ColoredParticle{
+ system: sys
+ particles: ["redTeam"]
+ image: "pics/blur-circle3.png"
+ color: "#0028060A"
+ colorVariation: 0.1
+ z: 0
+ }
+ ColoredParticle{
+ system: sys
+ particles: ["greenTeam"]
+ image: "pics/blur-circle3.png"
+ color: "#0006280A"
+ colorVariation: 0.1
+ z: 0
+ }
+ ColoredParticle{
+ system: sys
+ particles: ["blaster"]
+ image: "pics/star2.png"
+ //color: "#0F282406"
+ color: "#0F484416"
+ colorVariation: 0.2
+ z: 2
+ }
+ ColoredParticle{
+ system: sys
+ particles: ["laser"]
+ image: "pics/star3.png"
+ //color: "#00123F68"
+ color: "#00428FF8"
+ colorVariation: 0.2
+ z: 2
+ }
+ ColoredParticle{
+ system: sys
+ particles: ["cannon"]
+ image: "pics/particle.png"
+ color: "#80FFAAFF"
+ colorVariation: 0.1
+ z: 2
+ }
+ ColoredParticle{
+ system: sys
+ particles: ["cannonCore"]
+ image: "pics/particle.png"
+ color: "#00666666"
+ colorVariation: 0.8
+ z: 1
+ }
+ ColoredParticle{
+ system: sys
+ particles: ["cannonWake"]
+ image: "pics/star.png"
+ color: "#00CCCCCC"
+ colorVariation: 0.2
+ z: 1
+ }
+ ColoredParticle{
+ system: sys
+ particles: ["frigateShield"]
+ image: "pics/blur-circle2.png"
+ color: "#00000000"
+ colorVariation: 0.05
+ blueVariation: 0.5
+ greenVariation: 0.1
+ z: 3
+ }
+ SpriteParticle{
+ system: sys
+ particles: ["cruiserArmor"]
+ z: 1
+ sprites:[Sprite{
+ id: spinState
+ name: "spinning"
+ source: "pics/meteor.png"
+ frames: 35
+ duration: 40
+ to: {"death":0, "spinning":1}
+ },Sprite{
+ name: "death"
+ source: "pics/meteor_explo.png"
+ frames: 22
+ duration: 40
+ to: {"null":1}
+ }, Sprite{
+ name: "null"
+ source: "pics/nullRock.png"
+ frames: 1
+ duration: 1000
+ }
+ ]
+ }
+ FollowEmitter{
+ system: sys
+ particle: "cannonWake"
+ follow: "cannon"
+ particlesPerParticlePerSecond: 64
+ particleDuration: 600
+ speed: AngleVector{ angleVariation: 360; magnitude: 48}
+ particleSize: 16
+ particleEndSize: 8
+ particleSizeVariation: 2
+ emitting: true
+ width: 1000//XXX: Terrible hack
+ height: 1000
+ }
+ FollowEmitter{
+ system: sys
+ particle: "cannonCore"
+ follow: "cannon"
+ particlesPerParticlePerSecond: 256
+ particleDuration: 128
+ particleSize: 24
+ particleEndSize: 8
+ emitting: true
+ width: 1000//XXX: Terrible hack
+ height: 1000
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/SequentialLoader.qml b/demos/declarative/plasmapatrol/content/SequentialLoader.qml
new file mode 100644
index 0000000000..85a979b222
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/SequentialLoader.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+Item{
+ id: container
+ //TODO: Somehow get particles into this?
+ property list<Component> pages
+ property Item cur: null
+ property int at: 0
+ function advance(){
+ if(cur != null)
+ cur.destroy();
+ cur = pages[at++].createObject(container);
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/Ship.qml b/demos/declarative/plasmapatrol/content/Ship.qml
new file mode 100644
index 0000000000..0ccea94221
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/Ship.qml
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+Item {
+ id: me
+ //Reflective Properties
+ width: shipLoader.width
+ height: shipLoader.height
+ //Transfered Properties
+ property int hp: 100//shipLoader.item.maxHP
+ property real dodge: shipLoader.item.initialDodge
+ property ParticleSystem system
+ property int targetIdx: 0
+ property Item target: targets[targetIdx] == undefined?null:targets[targetIdx]
+ Connections{
+ target: me.target
+ onHpChanged: if(me.target.hp<=0) me.targetIdx++;
+ }
+ property list<Item> targets
+ property string shipParticle: "default"//Per team colors?
+ property int gunType: 0
+ property int shipType: 0
+ Component{
+ id: sloopComp
+ Sloop{
+ system: me.system
+ target: me.target
+ shipParticle: me.shipParticle
+ gunType: me.gunType
+ hp: me.hp
+ dodge: me.dodge
+ }
+ }
+ Component{
+ id: frigateComp
+ Frigate{
+ system: me.system
+ target: me.target
+ shipParticle: me.shipParticle
+ gunType: me.gunType
+ hp: me.hp
+ dodge: me.dodge
+ }
+ }
+ Component{
+ id: cruiserComp
+ Cruiser{
+ system: me.system
+ target: me.target
+ shipParticle: me.shipParticle
+ gunType: me.gunType
+ hp: me.hp
+ dodge: me.dodge
+ }
+ }
+ Component{
+ id: dumbComp
+ Item{
+ property int maxHP: 0
+ property int initialDodge: 0
+ }
+ }
+ Loader{
+ id: shipLoader
+ sourceComponent:{ switch(shipType){
+ case 1: sloopComp; break;
+ case 2: frigateComp; break;
+ case 3: cruiserComp; break;
+ default: dumbComp;
+ }
+ }
+ }
+}
diff --git a/demos/declarative/plasmapatrol/content/Sloop.qml b/demos/declarative/plasmapatrol/content/Sloop.qml
new file mode 100644
index 0000000000..1b9bce7333
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/Sloop.qml
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+
+Item {
+ id: container
+ property int maxHP: 100
+ property int hp: maxHP
+ property real initialDodge: 0.5
+ property real dodge: initialDodge
+ property int blinkInterval: 800
+ onHpChanged: if(hp <= 0) target = container;
+ property ParticleSystem system//TODO: Ship abstraction
+ property Item target: container
+ property string shipParticle: "default"//Per team colors?
+ property int gunType: 0
+ width: 128
+ height: 128
+ TrailEmitter{
+ id: emitter
+ //TODO: Cooler would be an 'orbiting' affector
+ //TODO: On the subject, opacity and size should be grouped type 'overLife' if we can cram that in the particles
+ system: container.system
+ particle: container.shipParticle
+ shape: Ellipse{}
+
+ particlesPerSecond: hp > 0 ? hp + 20 : 0
+ particleDuration: blinkInterval
+ maxParticles: (maxHP + 20)
+
+ acceleration: AngleVector{angleVariation: 360; magnitude: 8}
+
+ particleSize: 24
+ particleEndSize: 4
+ particleSizeVariation: 8
+ width: 16
+ height: 16
+ x: 64
+ y: 64
+ Behavior on x{NumberAnimation{duration:blinkInterval}}
+ Behavior on y{NumberAnimation{duration:blinkInterval}}
+ Timer{
+ interval: blinkInterval
+ running: true
+ repeat: true
+ onTriggered: {
+ emitter.x = Math.random() * 48 + 32
+ emitter.y = Math.random() * 48 + 32
+ }
+ }
+ }
+ Hardpoint{
+ anchors.centerIn: parent
+ id: gun2
+ system: container.system
+ show: container.hp > 0
+ hardpointType: gunType
+ }
+ Timer{
+ id: fireControl
+ interval: 800
+ running: root.readySetGo
+ repeat: true
+ onTriggered:{
+ gun2.fireAt(container.target);
+ }
+ }
+
+}
diff --git a/demos/declarative/plasmapatrol/content/pics/TitleText.png b/demos/declarative/plasmapatrol/content/pics/TitleText.png
new file mode 100644
index 0000000000..dc3acebe39
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/TitleText.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/content/pics/blur-circle2.png b/demos/declarative/plasmapatrol/content/pics/blur-circle2.png
new file mode 100644
index 0000000000..f7c9f3e98e
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/blur-circle2.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/content/pics/blur-circle3.png b/demos/declarative/plasmapatrol/content/pics/blur-circle3.png
new file mode 100644
index 0000000000..dbc39cb16e
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/blur-circle3.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/content/pics/finalfrontier.png b/demos/declarative/plasmapatrol/content/pics/finalfrontier.png
new file mode 100644
index 0000000000..2ba1815230
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/finalfrontier.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/content/pics/meteor.png b/demos/declarative/plasmapatrol/content/pics/meteor.png
new file mode 100644
index 0000000000..e8c368aea7
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/meteor.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/content/pics/meteor_explo.png b/demos/declarative/plasmapatrol/content/pics/meteor_explo.png
new file mode 100644
index 0000000000..4297245d49
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/meteor_explo.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/content/pics/nullRock.png b/demos/declarative/plasmapatrol/content/pics/nullRock.png
new file mode 100644
index 0000000000..4076327a1a
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/nullRock.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/content/pics/particle.png b/demos/declarative/plasmapatrol/content/pics/particle.png
new file mode 100644
index 0000000000..5c83896d22
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/particle.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/content/pics/star.png b/demos/declarative/plasmapatrol/content/pics/star.png
new file mode 100644
index 0000000000..0d592cfa87
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/star.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/content/pics/star2.png b/demos/declarative/plasmapatrol/content/pics/star2.png
new file mode 100644
index 0000000000..bb55c44788
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/star2.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/content/pics/star3.png b/demos/declarative/plasmapatrol/content/pics/star3.png
new file mode 100644
index 0000000000..636a25f480
--- /dev/null
+++ b/demos/declarative/plasmapatrol/content/pics/star3.png
Binary files differ
diff --git a/demos/declarative/plasmapatrol/plasmapatrol.qml b/demos/declarative/plasmapatrol/plasmapatrol.qml
new file mode 100644
index 0000000000..3a7b217618
--- /dev/null
+++ b/demos/declarative/plasmapatrol/plasmapatrol.qml
@@ -0,0 +1,386 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+import "content"
+
+Rectangle {
+ id: root
+ property bool readySetGo: false
+ //Debugging
+ property int hits: 0
+ property int misses: 0
+ property real ratio: hits/(misses?misses:1)
+ //Move to JS file?
+ property Ship redVar1: Ship{shipType: 1; gunType: 1}
+ property Ship redVar2: Ship{shipType: 1; gunType: 2}
+ property Ship redVar3: Ship{shipType: 1; gunType: 3}
+ property Ship greenVar1: Ship{shipType: 3; gunType: 1}
+ property Ship greenVar2: Ship{shipType: 2; gunType: 2}
+ property Ship greenVar3: Ship{shipType: 1; gunType: 3}
+ property string winner: "0"
+ property int players: 0
+ function aiSet(ship){
+ ship.gunType = Math.floor(Math.random() * 3) + 1
+ ship.shipType = Math.floor(Math.random() * 3) + 1
+ }
+
+ width: 360
+ height: 600
+ color: "black"
+ SequentialLoader{
+ anchors.fill: parent
+ //General Children
+ Image{
+ anchors.centerIn: parent
+ source: "content/pics/finalfrontier.png"
+ }
+ ParticleSystem{
+ id: particles
+ }
+ PlasmaPatrolParticles{ sys: particles; z: 100 }//Renders all particles on the one plane
+ //Component parts
+ id: pageControl
+ Component.onCompleted: advance();
+ pages:[
+ Component{Item{
+ id: menu
+ width: root.width
+ height: root.height
+ Column{
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ spacing: 8
+ Item{
+ id: title
+ width: root.width
+ height: 240
+ TrailEmitter{
+ anchors.fill: parent
+ system: particles
+ emitting: true
+ particle: "default"
+ particlesPerSecond: 1200
+ particleDuration: 1200
+ shape: Mask{source:"content/pics/TitleText.png"}
+ particleSize: 16
+ particleEndSize: 0
+ particleSizeVariation: 8
+ speed: AngleVector{angleVariation:360; magnitudeVariation: 6}
+ }
+ }
+ Button{
+ text: "1P"
+ onClicked: {root.players = 1; pageControl.advance();}
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Button{
+ text: "2P"
+ onClicked: {root.players = 2; pageControl.advance();}
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Button{
+ text: "Demo"
+ anchors.horizontalCenter: parent.horizontalCenter
+ onClicked: {root.players = 0;
+ aiSet(redVar1);
+ aiSet(redVar2);
+ aiSet(redVar3);
+ aiSet(greenVar1);
+ aiSet(greenVar2);
+ aiSet(greenVar3);
+ pageControl.at = 5;//TODO: Not a magic number
+ pageControl.advance();}
+ }
+ Button{
+ text: "Help"
+ anchors.horizontalCenter: parent.horizontalCenter
+ onClicked: {
+ pageControl.at = 7;//TODO: Not a magic number
+ pageControl.advance();
+ }
+ }
+ Button{
+ text: "Quit"
+ anchors.horizontalCenter: parent.horizontalCenter
+ onClicked: Qt.quit();
+ }
+ }
+ }},
+ Component{Item{
+ id: p1Screen
+ z: 101
+ width: root.width
+ height: root.height
+ Rectangle{
+ anchors.fill: parent
+ color: "red"
+ }
+ Text{
+ anchors.centerIn: parent
+ color: "white"
+ font.pixelSize: 64
+ font.bold: true
+ text: "Player\n 1"
+ horizontalAlignment: Text.AlignHCenter
+ }
+ MouseArea{
+ anchors.fill: parent
+ onClicked: pageControl.advance()
+ }
+ }},
+ Component{Item{
+ id: p1Choices
+ z: 3
+ width: root.width
+ height: root.height
+ Rectangle{
+ color: "black"
+ anchors.fill: parent
+ }
+ Column{
+ spacing: 16
+ width: root.width
+ anchors.horizontalCenter: parent.horizontalCenter
+ ChoiceBox{
+ target: redVar1
+ system: particles
+ }
+ ChoiceBox{
+ target: redVar2
+ system: particles
+ }
+ ChoiceBox{
+ target: redVar3
+ system: particles
+ }
+ Button{
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "Next"
+ onClicked: {
+ if(root.players < 2){
+ aiSet(greenVar1);
+ aiSet(greenVar2);
+ aiSet(greenVar3);
+ pageControl.at = 5;//TODO: Not a magic number
+ }
+ pageControl.advance();
+ }
+ }
+ }
+ }},
+ Component{Item{
+ id: p2Screen
+ z: 101
+ width: root.width
+ height: root.height
+ Rectangle{
+ anchors.fill: parent
+ color: "green"
+ }
+ Text{
+ anchors.centerIn: parent
+ color: "white"
+ font.pixelSize: 64
+ font.bold: true
+ text: "Player\n 2"
+ horizontalAlignment: Text.AlignHCenter
+ }
+ MouseArea{
+ anchors.fill: parent
+ onClicked: pageControl.advance()
+ }
+ }},
+ Component{Item{
+ id: p2Choices
+ z: 1
+ width: root.width
+ height: root.height
+ Rectangle{
+ color: "black"
+ anchors.fill: parent
+ }
+ Column{
+ spacing: 16
+ width: root.width
+ anchors.horizontalCenter: parent.horizontalCenter
+ ChoiceBox{
+ target: greenVar1
+ system: particles
+ }
+ ChoiceBox{
+ target: greenVar2
+ system: particles
+ }
+ ChoiceBox{
+ target: greenVar3
+ system: particles
+ }
+ Button{
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "Next"
+ onClicked: pageControl.advance()
+ }
+ }
+ }},
+ Component{Item{
+ id: arena
+ width: root.width
+ height: root.height
+ z: 0
+ Component.onCompleted: root.readySetGo = true
+ Component.onDestruction: root.readySetGo = false
+ property bool victory: redShip3.hp <= 0 || greenShip3.hp <=0
+ onVictoryChanged: {
+ if(redShip3.hp <= 0){
+ if(greenShip3.hp <= 0){
+ root.winner = "1&2"
+ }else{
+ root.winner = "2"
+ }
+ }else{
+ root.winner = "1"
+ }
+ winTimer.start()
+ }
+ Timer{
+ id: winTimer
+ interval: 1200
+ repeat: false
+ running: false
+ onTriggered: pageControl.advance();
+ }
+ Ship{
+ id: redShip1
+ shipParticle: "redTeam"
+ system: particles
+ x: 180-64
+ y: 128
+ shipType: redVar1.shipType
+ gunType: redVar1.gunType
+ targets: [greenShip1, greenShip2, greenShip3]
+ }
+ Ship{
+ id: redShip2
+ shipParticle: "redTeam"
+ system: particles
+ x: 0
+ y: 0
+ shipType: redVar2.shipType
+ gunType: redVar2.gunType
+ targets: [greenShip1, greenShip2, greenShip3]
+ }
+ Ship{
+ id: redShip3
+ shipParticle: "redTeam"
+ system: particles
+ x: 360-128
+ y: 0
+ shipType: redVar3.shipType
+ gunType: redVar3.gunType
+ targets: [greenShip1, greenShip2, greenShip3]
+ }
+
+ Ship{
+ id: greenShip1
+ shipParticle: "greenTeam"
+ system: particles
+ x: 180-64
+ y: 600 - 128 - 128
+ shipType: greenVar1.shipType
+ gunType: greenVar1.gunType
+ targets: [redShip1, redShip2, redShip3]
+ }
+ Ship{
+ id: greenShip2
+ shipParticle: "greenTeam"
+ system: particles
+ x: 0
+ y: 600-128
+ shipType: greenVar2.shipType
+ gunType: greenVar2.gunType
+ targets: [redShip1, redShip2, redShip3]
+ }
+ Ship{
+ id: greenShip3
+ shipParticle: "greenTeam"
+ system: particles
+ x: 360 - 128
+ y: 600 - 128
+ shipType: greenVar3.shipType
+ gunType: greenVar3.gunType
+ targets: [redShip1, redShip2, redShip3]
+ }
+ }},
+ Component{Item{
+ id: winScreen
+ z: 101
+ width: root.width
+ height: root.height
+ /*
+ Rectangle{
+ anchors.fill: parent
+ color: "black"
+ }
+ */
+ Text{//TODO: Particle Text?
+ anchors.fill: parent
+ color: "white"
+ font.pixelSize: 64
+ font.bold: true
+ text: "Player " + root.winner + " wins!"
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ MouseArea{
+ anchors.fill: parent
+ onClicked: {pageControl.at = 0; pageControl.advance();}
+ }
+ }},
+ Component{
+ HelpScreens{
+ onExitDesired: {pageControl.at = 0; pageControl.advance();}
+ }
+ }
+ ]
+ }
+}
diff --git a/demos/declarative/samegame/SamegameCore/BoomBlock.qml b/demos/declarative/samegame/SamegameCore/BoomBlock.qml
index 009aeca2c6..3d11fb9df2 100644
--- a/demos/declarative/samegame/SamegameCore/BoomBlock.qml
+++ b/demos/declarative/samegame/SamegameCore/BoomBlock.qml
@@ -39,8 +39,8 @@
**
****************************************************************************/
-import QtQuick 1.1
-import Qt.labs.particles 1.0
+import QtQuick 2.0
+import Qt.labs.particles 2.0
Item {
id: block
@@ -71,26 +71,28 @@ Item {
Behavior on opacity { NumberAnimation { duration: 200 } }
anchors.fill: parent
}
-
- Particles {
+ TrailEmitter {
id: particles
-
- width: 1; height: 1
- anchors.centerIn: parent
-
- emissionRate: 0
- lifeSpan: 700; lifeSpanDeviation: 600
- angle: 0; angleDeviation: 360;
- velocity: 100; velocityDeviation: 30
- source: {
+ system: particleSystem
+ particle: {
if(type == 0){
- "pics/redStar.png";
+ "red";
} else if (type == 1) {
- "pics/blueStar.png";
+ "blue";
} else {
- "pics/greenStar.png";
+ "green";
}
}
+ anchors.fill: parent
+
+ speed: DirectedVector{targetX: block.width/2; targetY: block.height/2; magnitude: -60; magnitudeVariation: 60}
+ shape: Ellipse{fill:true}
+ emitting: false;
+ particleDuration: 700; particleDurationVariation: 100
+ particlesPerSecond: 1000
+ maxParticles: 100 //only fires 0.1s bursts (still 2x old number, ColoredParticle wants less than 16000 max though)
+ particleSize: 28
+ particleEndSize: 14
}
states: [
@@ -101,7 +103,7 @@ Item {
State {
name: "DeathState"; when: dying == true
- StateChangeScript { script: particles.burst(50); }
+ StateChangeScript { script: particles.pulse(0.1); }
PropertyChanges { target: img; opacity: 0 }
StateChangeScript { script: block.destroy(1000); }
}
diff --git a/demos/declarative/samegame/SamegameCore/Button.qml b/demos/declarative/samegame/SamegameCore/Button.qml
index b2b232ca8e..8bcca5b5d5 100644
--- a/demos/declarative/samegame/SamegameCore/Button.qml
+++ b/demos/declarative/samegame/SamegameCore/Button.qml
@@ -39,7 +39,7 @@
**
****************************************************************************/
-import QtQuick 1.1
+import QtQuick 2.0
Rectangle {
id: container
diff --git a/demos/declarative/samegame/SamegameCore/Dialog.qml b/demos/declarative/samegame/SamegameCore/Dialog.qml
index ecac475826..ee1b51006a 100644
--- a/demos/declarative/samegame/SamegameCore/Dialog.qml
+++ b/demos/declarative/samegame/SamegameCore/Dialog.qml
@@ -39,23 +39,26 @@
**
****************************************************************************/
-import QtQuick 1.1
+import QtQuick 2.0
Rectangle {
id: page
property Item text: dialogText
+ property bool open: false
signal closed
signal opened
function forceClose() {
- if(page.opacity == 0)
+ if(!open)
return; //already closed
+ page.open = false;
page.closed();
page.opacity = 0;
}
function show(txt) {
+ page.open = true;
page.opened();
dialogText.text = txt;
page.opacity = 1;
diff --git a/demos/declarative/samegame/SamegameCore/pics/blueStar.png b/demos/declarative/samegame/SamegameCore/pics/blueStar.png
deleted file mode 100644
index ff9588f80a..0000000000
--- a/demos/declarative/samegame/SamegameCore/pics/blueStar.png
+++ /dev/null
Binary files differ
diff --git a/demos/declarative/samegame/SamegameCore/pics/greenStar.png b/demos/declarative/samegame/SamegameCore/pics/greenStar.png
deleted file mode 100644
index cd06854719..0000000000
--- a/demos/declarative/samegame/SamegameCore/pics/greenStar.png
+++ /dev/null
Binary files differ
diff --git a/demos/declarative/samegame/SamegameCore/pics/particle.png b/demos/declarative/samegame/SamegameCore/pics/particle.png
new file mode 100644
index 0000000000..5c83896d22
--- /dev/null
+++ b/demos/declarative/samegame/SamegameCore/pics/particle.png
Binary files differ
diff --git a/demos/declarative/samegame/SamegameCore/pics/redStar.png b/demos/declarative/samegame/SamegameCore/pics/redStar.png
deleted file mode 100644
index 0a4dffe583..0000000000
--- a/demos/declarative/samegame/SamegameCore/pics/redStar.png
+++ /dev/null
Binary files differ
diff --git a/demos/declarative/samegame/SamegameCore/pics/star.png b/demos/declarative/samegame/SamegameCore/pics/star.png
deleted file mode 100644
index defbde53ca..0000000000
--- a/demos/declarative/samegame/SamegameCore/pics/star.png
+++ /dev/null
Binary files differ
diff --git a/demos/declarative/samegame/SamegameCore/samegame.js b/demos/declarative/samegame/SamegameCore/samegame.js
index bb587bc6f3..4c5cbe5bb3 100755
--- a/demos/declarative/samegame/SamegameCore/samegame.js
+++ b/demos/declarative/samegame/SamegameCore/samegame.js
@@ -4,10 +4,11 @@ var maxColumn = 10;
var maxRow = 15;
var maxIndex = maxColumn*maxRow;
var board = new Array(maxIndex);
-var blockSrc = "SamegameCore/BoomBlock.qml";
+var blockSrc = "BoomBlock.qml";
var scoresURL = "";
var gameDuration;
var component = Qt.createComponent(blockSrc);
+var highScoreBar = 0;
// Index function used instead of a 2D array
function index(column, row)
@@ -152,11 +153,15 @@ function victoryCheck()
// Checks for game over
if (deservesBonus || !(floodMoveCheck(0, maxRow - 1, -1))) {
gameDuration = new Date() - gameDuration;
- nameInputDialog.show("You won! Please enter your name: ");
- nameInputDialog.initialWidth = nameInputDialog.text.width + 20;
- if (nameInputDialog.name == "")
- nameInputDialog.width = nameInputDialog.initialWidth;
- nameInputDialog.text.opacity = 0; // Just a spacer
+ if(gameCanvas.score > highScoreBar){
+ nameInputDialog.show("You won! Please enter your name: ");
+ nameInputDialog.initialWidth = nameInputDialog.text.width + 20;
+ if (nameInputDialog.name == "")
+ nameInputDialog.width = nameInputDialog.initialWidth;
+ nameInputDialog.text.opacity = 0; // Just a spacer
+ }else{
+ dialog.show("You won!");
+ }
}
}
@@ -203,6 +208,30 @@ function createBlock(column,row)
return true;
}
+function initHighScoreBar()
+{
+ if(scoresURL != "")
+ return true;//don't query remote scores
+ var db = openDatabaseSync(
+ "SameGameScores",
+ "1.0",
+ "Local SameGame High Scores",
+ 100
+ );
+ db.transaction(
+ function(tx) {
+ tx.executeSql('CREATE TABLE IF NOT EXISTS Scores(name TEXT, score NUMBER, gridSize TEXT, time NUMBER)');
+ // Only show results for the current grid size
+ var rs = tx.executeSql('SELECT * FROM Scores WHERE gridSize = "'
+ + maxColumn + "x" + maxRow + '" ORDER BY score desc LIMIT 10');
+ if(rs.rows.length < 10)
+ highScoreBar = 0;
+ else
+ highScoreBar = rs.rows.item(rs.rows.length - 1).score;
+ }
+ );
+}
+
function saveHighScore(name)
{
if (scoresURL != "")
@@ -235,6 +264,8 @@ function saveHighScore(name)
+ rs.rows.item(i).score + ' points in '
+ rs.rows.item(i).time + ' seconds.\n';
}
+ if(rs.rows.length == 10)
+ highScoreBar = rs.rows.item(9).score;
dialog.show(r);
}
);
diff --git a/demos/declarative/samegame/samegame.qml b/demos/declarative/samegame/samegame.qml
index ab64156278..0defdeec3c 100644
--- a/demos/declarative/samegame/samegame.qml
+++ b/demos/declarative/samegame/samegame.qml
@@ -39,13 +39,14 @@
**
****************************************************************************/
-import QtQuick 1.1
+import QtQuick 2.0
+import Qt.labs.particles 2.0
import "SamegameCore"
import "SamegameCore/samegame.js" as Logic
Rectangle {
id: screen
- width: 490; height: 720
+ width: 360; height: 640
property bool inAnotherDemo: false //Samegame often is just plonked straight into other demos
SystemPalette { id: activePalette }
@@ -74,6 +75,36 @@ Rectangle {
anchors.fill: parent; onClicked: Logic.handleClick(mouse.x,mouse.y);
}
}
+ Item{
+ ParticleSystem{ id: particleSystem; }
+ ColoredParticle {
+ system: particleSystem
+ particles: ["red"]
+ color: Qt.darker("red");//Actually want desaturated...
+ image: "SamegameCore/pics/particle.png"
+ colorVariation: 0.4
+ alpha: 0.1
+ }
+ ColoredParticle {
+ system: particleSystem
+ particles: ["green"]
+ color: Qt.darker("green");//Actually want desaturated...
+ image: "SamegameCore/pics/particle.png"
+ colorVariation: 0.4
+ alpha: 0.1
+ }
+ ColoredParticle {
+ system: particleSystem
+ particles: ["blue"]
+ color: Qt.darker("blue");//Actually want desaturated...
+ image: "SamegameCore/pics/particle.png"
+ colorVariation: 0.4
+ alpha: 0.1
+ }
+ id: aboveGameCanvas
+ anchors.fill: gameCanvas
+ z: gameCanvas.z + 1
+ }
}
Dialog { id: dialog; anchors.centerIn: parent; z: 21 }
diff --git a/demos/declarative/shadereffects/Slider.qml b/demos/declarative/shadereffects/Slider.qml
new file mode 100644
index 0000000000..e31335d984
--- /dev/null
+++ b/demos/declarative/shadereffects/Slider.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ property real value: bar.x / (foo.width - bar.width)
+ Item {
+ id: foo
+ width: parent.width - 4
+ height: 6
+ anchors.centerIn: parent
+
+ Rectangle {
+ height: parent.height
+ anchors.left: parent.left
+ anchors.right: bar.horizontalCenter
+ color: "blue"
+ radius: 3
+ }
+ Rectangle {
+ height: parent.height
+ anchors.left: bar.horizontalCenter
+ anchors.right: parent.right
+ color: "gray"
+ radius: 3
+ }
+ Rectangle {
+ anchors.fill: parent
+ color: "transparent"
+ radius: 3
+ border.width: 2
+ border.color: "black"
+ }
+
+ Rectangle {
+ id: bar
+ y: -7
+ width: 20
+ height: 20
+ radius: 15
+ color: "white"
+ border.width: 2
+ border.color: "black"
+ MouseArea {
+ anchors.fill: parent
+ drag.target: parent
+ drag.axis: Drag.XAxis
+ drag.minimumX: 0
+ drag.maximumX: foo.width - parent.width
+ }
+ }
+ }
+}
+
diff --git a/demos/declarative/shadereffects/face-smile.png b/demos/declarative/shadereffects/face-smile.png
new file mode 100644
index 0000000000..3d66d72578
--- /dev/null
+++ b/demos/declarative/shadereffects/face-smile.png
Binary files differ
diff --git a/demos/declarative/shadereffects/qt-logo.png b/demos/declarative/shadereffects/qt-logo.png
new file mode 100644
index 0000000000..7d3e97eb36
--- /dev/null
+++ b/demos/declarative/shadereffects/qt-logo.png
Binary files differ
diff --git a/demos/declarative/shadereffects/shader-demo.qml b/demos/declarative/shadereffects/shader-demo.qml
new file mode 100644
index 0000000000..1226064a5d
--- /dev/null
+++ b/demos/declarative/shadereffects/shader-demo.qml
@@ -0,0 +1,295 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Image {
+ width: 640
+ height: 360
+ source: "../snake/content/pics/background.png"
+
+ ShaderEffectSource {
+ id: theSource
+ sourceItem: theItem
+ smooth: true
+ }
+
+ function saturate(x) {
+ return Math.min(Math.max(x, 0), 1)
+ }
+
+ function sliderToColor(x) {
+ return Qt.rgba(saturate(Math.max(2 - 6 * x, 6 * x - 4)),
+ saturate(Math.min(6 * x, 4 - 6 * x)),
+ saturate(Math.min(6 * x - 2, 6 - 6 * x)))
+ }
+
+ Grid {
+ anchors.centerIn: parent
+ columns: 3
+
+ Item {
+ id: theItem
+ width: 180
+ height: 180
+ ListView {
+ anchors.centerIn: parent
+ width: 160
+ height: 140
+ clip: true
+ snapMode: ListView.SnapOneItem
+ model: VisualItemModel {
+ Text {
+ width: 160
+ height: 140
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: 120
+ font.family: "Times"
+ color: "blue"
+ text: "Qt"
+ }
+ Image {
+ width: 160
+ height: 140
+ source: "qt-logo.png"
+ smooth: true
+ }
+ Image {
+ width: 160
+ height: 140
+ source: "face-smile.png"
+ smooth: true
+ }
+ }
+ }
+ }
+ ShaderEffectItem {
+ width: 180
+ height: 180
+ property variant source: theSource
+ property real amplitude: 0.04 * wobbleSlider.value
+ property real frequency: 20
+ property real time: 0
+ NumberAnimation on time { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 600 }
+ fragmentShader:
+ "uniform highp float amplitude;" +
+ "uniform highp float frequency;" +
+ "uniform highp float time;" +
+ "uniform sampler2D source;" +
+ "varying highp vec2 qt_TexCoord0;" +
+ "void main() {" +
+ " highp vec2 p = sin(time + frequency * qt_TexCoord0);" +
+ " gl_FragColor = texture2D(source, qt_TexCoord0 + amplitude * vec2(p.y, -p.x));" +
+ "}"
+ Slider {
+ id: wobbleSlider
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ height: 40
+ }
+ }
+ ShaderEffectItem {
+ width: 180
+ height: 180
+ property variant source: theSource
+ property variant shadow: ShaderEffectSource {
+ smooth: true
+ sourceItem: ShaderEffectItem {
+ width: theItem.width
+ height: theItem.height
+ property variant delta: Qt.size(0.0, 1.0 / height)
+ property variant source: ShaderEffectSource {
+ smooth: true
+ sourceItem: ShaderEffectItem {
+ width: theItem.width
+ height: theItem.height
+ property variant delta: Qt.size(1.0 / width, 0.0)
+ property variant source: theSource
+ fragmentShader: "
+ uniform sampler2D source;
+ uniform highp vec2 delta;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ gl_FragColor = 0.0538 * texture2D(source, qt_TexCoord0 - 3.182 * delta)
+ + 0.3229 * texture2D(source, qt_TexCoord0 - 1.364 * delta)
+ + 0.2466 * texture2D(source, qt_TexCoord0)
+ + 0.3229 * texture2D(source, qt_TexCoord0 + 1.364 * delta)
+ + 0.0538 * texture2D(source, qt_TexCoord0 + 3.182 * delta);
+ }"
+ }
+ }
+ fragmentShader: "
+ uniform sampler2D source;
+ uniform highp vec2 delta;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ gl_FragColor = 0.0538 * texture2D(source, qt_TexCoord0 - 3.182 * delta)
+ + 0.3229 * texture2D(source, qt_TexCoord0 - 1.364 * delta)
+ + 0.2466 * texture2D(source, qt_TexCoord0)
+ + 0.3229 * texture2D(source, qt_TexCoord0 + 1.364 * delta)
+ + 0.0538 * texture2D(source, qt_TexCoord0 + 3.182 * delta);
+ }"
+ }
+ }
+ property real angle: 0
+ property variant offset: Qt.point(15.0 * Math.cos(angle), 15.0 * Math.sin(angle))
+ NumberAnimation on angle { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 6000 }
+ property variant delta: Qt.size(offset.x / width, offset.y / height)
+ property real darkness: shadowSlider.value
+ fragmentShader: "
+ uniform highp vec2 offset;
+ uniform sampler2D source;
+ uniform sampler2D shadow;
+ uniform highp float darkness;
+ uniform highp vec2 delta;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ lowp vec4 fg = texture2D(source, qt_TexCoord0);
+ lowp vec4 bg = texture2D(shadow, qt_TexCoord0 + delta);
+ gl_FragColor = fg + vec4(0., 0., 0., darkness * bg.a) * (1. - fg.a);
+ }"
+ Slider {
+ id: shadowSlider
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ height: 40
+ }
+ }
+ ShaderEffectItem {
+ width: 180
+ height: 180
+ property variant source: theSource
+ property variant delta: Qt.size(0.5 / width, 0.5 / height)
+ fragmentShader: "
+ uniform sampler2D source;
+ uniform highp vec2 delta;
+ uniform highp float qt_Opacity;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ lowp vec4 tl = texture2D(source, qt_TexCoord0 - delta);
+ lowp vec4 tr = texture2D(source, qt_TexCoord0 + vec2(delta.x, -delta.y));
+ lowp vec4 bl = texture2D(source, qt_TexCoord0 - vec2(delta.x, -delta.y));
+ lowp vec4 br = texture2D(source, qt_TexCoord0 + delta);
+ lowp vec4 gx = (tl + bl) - (tr + br);
+ lowp vec4 gy = (tl + tr) - (bl + br);
+ gl_FragColor.xyz = vec3(0.);
+ gl_FragColor.w = clamp(dot(sqrt(gx * gx + gy * gy), vec4(1.)), 0., 1.) * qt_Opacity;
+ }"
+ }
+ ShaderEffectItem {
+ width: 180
+ height: 180
+ property variant source: theSource
+ property color tint: sliderToColor(colorizeSlider.value)
+ fragmentShader: "
+ uniform sampler2D source;
+ uniform lowp vec4 tint;
+ uniform lowp float qt_Opacity;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ lowp vec4 c = texture2D(source, qt_TexCoord0);
+ lowp float lo = min(min(c.x, c.y), c.z);
+ lowp float hi = max(max(c.x, c.y), c.z);
+ gl_FragColor = qt_Opacity * vec4(mix(vec3(lo), vec3(hi), tint.xyz), c.w);
+ }"
+ Slider {
+ id: colorizeSlider
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ height: 40
+ }
+ }
+ ShaderEffectItem {
+ width: 180
+ height: 180
+ mesh: GridMesh { resolution: Qt.size(10, 10) }
+ property variant source: theSource
+ property real bend: 0
+ property real minimize: 0
+ property real side: genieSlider.value
+ SequentialAnimation on bend {
+ loops: Animation.Infinite
+ NumberAnimation { to: 1; duration: 700; easing.type: Easing.InOutSine }
+ PauseAnimation { duration: 1600 }
+ NumberAnimation { to: 0; duration: 700; easing.type: Easing.InOutSine }
+ PauseAnimation { duration: 1000 }
+ }
+ SequentialAnimation on minimize {
+ loops: Animation.Infinite
+ PauseAnimation { duration: 300 }
+ NumberAnimation { to: 1; duration: 700; easing.type: Easing.InOutSine }
+ PauseAnimation { duration: 1000 }
+ NumberAnimation { to: 0; duration: 700; easing.type: Easing.InOutSine }
+ PauseAnimation { duration: 1300 }
+ }
+ vertexShader: "
+ uniform highp mat4 qt_ModelViewProjectionMatrix;
+ uniform highp float bend;
+ uniform highp float minimize;
+ uniform highp float side;
+ uniform highp float width;
+ uniform highp float height;
+ attribute highp vec4 qt_Vertex;
+ attribute highp vec2 qt_MultiTexCoord0;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ qt_TexCoord0 = qt_MultiTexCoord0;
+ highp vec4 pos = qt_Vertex;
+ pos.y = mix(qt_Vertex.y, height, minimize);
+ highp float t = pos.y / height;
+ t = (3. - 2. * t) * t * t;
+ pos.x = mix(qt_Vertex.x, side * width, t * bend);
+ gl_Position = qt_ModelViewProjectionMatrix * pos;
+ }"
+ Slider {
+ id: genieSlider
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ height: 40
+ }
+ }
+ }
+}
diff --git a/doc/src/declarative/modules.qdoc b/doc/src/declarative/modules.qdoc
index dbc8806742..f2e24f2fa7 100644
--- a/doc/src/declarative/modules.qdoc
+++ b/doc/src/declarative/modules.qdoc
@@ -310,6 +310,7 @@ It is defined by a plain text file named "qmldir" that contains one or more line
<TypeName> [<InitialVersion>] <File>
internal <TypeName> <File>
plugin <Name> [<Path>]
+typeinfo <File>
\endcode
\bold {# <Comment>} lines are used for comments. They are ignored by the QML engine.
@@ -350,6 +351,14 @@ plugin file, or a relative path from the directory containing the \c qmldir file
containing the plugin file. By default the engine searches for the plugin library in the directory that contains the \c qmldir
file. The plugin search path can be queried with QDeclarativeEngine::pluginPathList() and modified using QDeclarativeEngine::addPluginPath(). When running the \l {QML Viewer}, use the \c -P option to add paths to the plugin search path.
+\bold {typeinfo <File>} lines add \l{Writing a qmltypes file}{type description files} to
+the module that can be read by QML tools such as Qt Creator to get information about the
+types defined by the module's plugins. <File> is the (relative) file name of a .qmltypes
+file.
+
+Without such a file QML tools may be unable to offer features such as code completion
+for the types defined in your plugins.
+
\section1 Debugging
@@ -358,5 +367,119 @@ when there are problems with finding and loading modules. See
\l{Debugging module imports} for more information.
+\section1 Writing a qmltypes file
+
+QML modules may refer to one or more type information files in their
+\l{Writing a qmldir file}{qmldir} file. These usually have the .qmltypes
+extension and are read by external tools to gain information about
+types defined in plugins.
+
+As such qmltypes files have no effect on the functionality of a QML module.
+Their only use is to allow tools such as Qt Creator to provide code completion,
+error checking and other functionality to users of your module.
+
+Any module that uses plugins should also ship a type description file.
+
+The best way to create a qmltypes file for your module is to generate it
+using the \c qmlplugindump tool that is provided with Qt.
+
+Example:
+If your module is in \c /tmp/imports/My/Module, you could run
+\code
+qmlplugindump My.Module 1.0 /tmp/imports > /tmp/imports/My/Module/mymodule.qmltypes
+\endcode
+to generate type information for your module. Afterwards, add the line
+\code
+typeinfo mymodule.qmltypes
+\endcode
+to \c /tmp/imports/My/Module/qmldir to register it.
+
+While the qmldump tool covers most cases, it does not work if:
+\list
+\o The plugin uses a \l{QDeclarativeCustomParser}. The component that uses
+ the custom parser will not get its members documented.
+\o The plugin can not be loaded. In particular if you cross-compiled
+ the plugin for a different architecture, qmldump will not be able to
+ load it.
+\endlist
+
+In case you have to create a qmltypes file manually or need to adjust
+an existing one, this is the file format:
+
+\qml
+import QtQuick.tooling 1.0
+
+// There always is a single Module object that contains all
+// Component objects.
+Module {
+ // A Component object directly corresponds to a type exported
+ // in a plugin with a call to qmlRegisterType.
+ Component {
+
+ // The name is a unique identifier used to refer to this type.
+ // It is recommended you simply use the C++ type name.
+ name: "QDeclarativeAbstractAnimation"
+
+ // The name of the prototype Component.
+ prototype: "QObject"
+
+ // The name of the default property.
+ defaultProperty: "animations"
+
+ // The name of the type containing attached properties
+ // and methods.
+ attachedType: "QDeclarativeAnimationAttached"
+
+ // The list of exports determines how a type can be imported.
+ // Each string has the format "URI/Name version" and matches the
+ // arguments to qmlRegisterType. Usually types are only exported
+ // once, if at all.
+ // If the "URI/" part of the string is missing that means the
+ // type should be put into the package defined by the URI the
+ // module was imported with.
+ // For example if this module was imported with 'import Foo 4.8'
+ // the Animation object would be found in the package Foo and
+ // QtQuick.
+ exports: [
+ "Animation 4.7",
+ "QtQuick/Animation 1.0"
+ ]
+
+ Property {
+ name: "animations";
+ type: "QDeclarativeAbstractAnimation"
+ // defaults to false, whether this property is read only
+ isReadonly: true
+ // defaults to false, whether the type of this property was a pointer in C++
+ isPointer: true
+ // defaults to false: whether the type actually is a QDeclarativeListProperty<type>
+ isList: true
+ }
+ Property { name: "loops"; type: "int" }
+ Property { name: "name"; type: "string" }
+ Property { name: "loopsEnum"; type: "Loops" }
+
+ Enum {
+ name: "Loops"
+ values: {
+ "Infinite": -2,
+ "OnceOnly": 1
+ }
+ }
+
+ // Signal and Method work the same way. The inner Parameter
+ // declarations also support the isReadonly, isPointer and isList
+ // attributes which mean the same as for Property
+ Method { name: "restart" }
+ Signal { name: "started" }
+ Signal {
+ name: "runningChanged"
+ Parameter { type: "bool" }
+ Parameter { name: "foo"; type: "bool" }
+ }
+ }
+}
+\endqml
+
*/
/
diff --git a/doc/src/declarative/qdeclarativeintro.qdoc b/doc/src/declarative/qdeclarativeintro.qdoc
index 02692de92c..ea2403ee76 100644
--- a/doc/src/declarative/qdeclarativeintro.qdoc
+++ b/doc/src/declarative/qdeclarativeintro.qdoc
@@ -320,6 +320,14 @@ Text {
In the element documentation grouped properties are shown using the 'dot' notation.
+While you can bind the entire group at once, like below, note that setting any of the
+grouped properties will result in setting the group and thus invalidate the binding.
+\qml
+Text {
+ font: otherText.font
+}
+\endqml
+
\section2 Attached Properties
\target attached-properties
diff --git a/doc/src/snippets/declarative/models/views-models-delegates.qml b/doc/src/snippets/declarative/models/views-models-delegates.qml
index 2f76856ca6..e02cb1a11f 100644
--- a/doc/src/snippets/declarative/models/views-models-delegates.qml
+++ b/doc/src/snippets/declarative/models/views-models-delegates.qml
@@ -37,6 +37,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+import QtQuick 1.0
//! [rectangle]
Rectangle {
diff --git a/doc/src/snippets/declarative/models/visual-model-and-view.qml b/doc/src/snippets/declarative/models/visual-model-and-view.qml
index 4d42b6585c..824d57230f 100644
--- a/doc/src/snippets/declarative/models/visual-model-and-view.qml
+++ b/doc/src/snippets/declarative/models/visual-model-and-view.qml
@@ -37,6 +37,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+import QtQuick 1.0
Rectangle {
width: 200; height: 200
diff --git a/doc/src/snippets/declarative/mousearea/mousearea-snippet.qml b/doc/src/snippets/declarative/mousearea/mousearea-snippet.qml
index 03473bafda..6f5b61a0b3 100644
--- a/doc/src/snippets/declarative/mousearea/mousearea-snippet.qml
+++ b/doc/src/snippets/declarative/mousearea/mousearea-snippet.qml
@@ -65,7 +65,6 @@ Rectangle {
//! [anchor fill]
Rectangle {
- id: button
width: 100; height: 100
//! [enable handlers]
@@ -79,7 +78,6 @@ Rectangle {
}
Rectangle {
- id: button
width: 100; height: 100
//! [mouse handlers]
diff --git a/doc/src/snippets/declarative/states/statechangescript.qml b/doc/src/snippets/declarative/states/statechangescript.qml
index aa1246d3fc..03d03f8a98 100644
--- a/doc/src/snippets/declarative/states/statechangescript.qml
+++ b/doc/src/snippets/declarative/states/statechangescript.qml
@@ -37,6 +37,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+
import QtQuick 1.0
Item {
diff --git a/examples/declarative/declarative.pro b/examples/declarative/declarative.pro
index 927294ade6..cbeb7e9e26 100644
--- a/examples/declarative/declarative.pro
+++ b/examples/declarative/declarative.pro
@@ -4,7 +4,8 @@ TEMPLATE = subdirs
SUBDIRS = \
cppextensions \
modelviews \
- tutorials
+ tutorials \
+ painteditem
# plugins uses a 'Time' class that conflicts with symbian e32std.h also defining a class of the same name
symbian:SUBDIRS -= plugins
diff --git a/examples/declarative/inputmethods/inputmethods.qmlproject b/examples/declarative/inputmethods/inputmethods.qmlproject
new file mode 100644
index 0000000000..d4909f8685
--- /dev/null
+++ b/examples/declarative/inputmethods/inputmethods.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ " ../exampleplugin " ]
+}
diff --git a/examples/declarative/inputmethods/spellcheck/Key.qml b/examples/declarative/inputmethods/spellcheck/Key.qml
new file mode 100644
index 0000000000..c95a3f0b2c
--- /dev/null
+++ b/examples/declarative/inputmethods/spellcheck/Key.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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 {
+ property string text
+ property string displayText
+ property alias font: keyText.font
+ property int key: 0
+
+ id: root
+ radius: 2
+
+ width: 28
+ height: 28
+
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "darkgrey" }
+ GradientStop { position: 1.0; color: "grey" }
+ }
+
+ Text {
+ id: keyText
+
+ anchors.fill: parent
+
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ font.pixelSize: 18
+ font.capitalization: keyboard.shift && displayText == "" ? Font.AllUppercase : Font.MixedCase
+
+ text: root.displayText != "" ? root.displayText : root.text
+
+ style: !mouseArea.pressed ? Text.Raised : Text.Normal
+ color: "white"
+ styleColor: "grey"
+ }
+
+ MouseArea {
+ id: mouseArea
+
+ anchors.fill: parent
+ onPressed: keyboard.keyPress(key, text)
+ onReleased: keyboard.keyRelease(key, text)
+ }
+}
diff --git a/examples/declarative/inputmethods/spellcheck/Keyboard.qml b/examples/declarative/inputmethods/spellcheck/Keyboard.qml
new file mode 100644
index 0000000000..533762e7ba
--- /dev/null
+++ b/examples/declarative/inputmethods/spellcheck/Keyboard.qml
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.inputcontext 1.0 as InputContext
+
+
+Rectangle {
+ id: keyboard
+
+ radius: 5
+ height: 122
+ width: 324
+
+ property bool shift: false
+
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "lightgrey" }
+ GradientStop { position: 1.0; color: "white" }
+ }
+
+ Column {
+ anchors.left: parent.left; anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+
+ spacing: 2
+
+ Row {
+ spacing: 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Key { key: Qt.Key_Q; text: "q"; }
+ Key { key: Qt.Key_W; text: "w"; }
+ Key { key: Qt.Key_E; text: "e"; }
+ Key { key: Qt.Key_R; text: "r"; }
+ Key { key: Qt.Key_T; text: "t"; }
+ Key { key: Qt.Key_Y; text: "y"; }
+ Key { key: Qt.Key_U; text: "u"; }
+ Key { key: Qt.Key_I; text: "i"; }
+ Key { key: Qt.Key_O; text: "o"; }
+ Key { key: Qt.Key_P; text: "p"; }
+ }
+ Row {
+ spacing: 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Key { key: Qt.Key_A; text: "a"; }
+ Key { key: Qt.Key_S; text: "s"; }
+ Key { key: Qt.Key_D; text: "d"; }
+ Key { key: Qt.Key_F; text: "f"; }
+ Key { key: Qt.Key_G; text: "g"; }
+ Key { key: Qt.Key_H; text: "h"; }
+ Key { key: Qt.Key_J; text: "j"; }
+ Key { key: Qt.Key_K; text: "k"; }
+ Key { key: Qt.Key_L; text: "l"; }
+ }
+ Row {
+ spacing: 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Key { key: Qt.Key_Shift; displayText: "shift"; width: 50 }
+ Key { key: Qt.Key_Z; text: "z"; }
+ Key { key: Qt.Key_X; text: "x"; }
+ Key { key: Qt.Key_C; text: "c"; }
+ Key { key: Qt.Key_V; text: "v"; }
+ Key { key: Qt.Key_B; text: "b"; }
+ Key { key: Qt.Key_N; text: "n"; }
+ Key { key: Qt.Key_M; text: "m"; }
+ Key { key: Qt.Key_Comma; text: ","; }
+ Key { key: Qt.Key_Period; text: "."; }
+ }
+
+ Row {
+ spacing: 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Key { key: Qt.Key_Enter; text: "\n"; displayText: "enter"; width: 90 }
+ Key { key: Qt.Key_Space; text: " "; displayText: "space"; width: 138}
+ Key { key: Qt.Key_Backspace; displayText: "backspace"; width: 90 }
+ }
+ }
+
+ function keyPress(key, text)
+ {
+ if (key == Qt.Key_Shift)
+ keyboard.shift = !keyboard.shift
+ else if (keyboard.shift)
+ InputContext.sendKeyPress(key, text.toUpperCase(), Qt.ShiftModifier)
+ else
+ InputContext.sendKeyPress(key, text)
+ }
+
+ function keyRelease(key, text)
+ {
+ if (key != Qt.Key_Shift) {
+ if (keyboard.shift) {
+ InputContext.sendKeyRelease(key, text.toUpperCase(), Qt.ShiftModifier)
+ keyboard.shift = false
+ } else {
+ InputContext.sendKeyRelease(key, text)
+ }
+ }
+ }
+}
diff --git a/examples/declarative/inputmethods/spellcheck/WordSuggestions.qml b/examples/declarative/inputmethods/spellcheck/WordSuggestions.qml
new file mode 100644
index 0000000000..5c4e9cb4a2
--- /dev/null
+++ b/examples/declarative/inputmethods/spellcheck/WordSuggestions.qml
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.inputcontext 1.0 as InputContext
+
+ListView {
+ property int globalX: InputContext.microFocus.x + ((InputContext.microFocus.width - width) / 2)
+ property int globalY: InputContext.microFocus.y + InputContext.microFocus.height
+
+ x: parent.mapToItem(null, globalX, globalY).x
+ y: parent.mapToItem(null, globalX, globalY).y
+
+ visible: suggestionModel.count > 0
+
+ width: 200
+ height: 70
+
+ InputContext.KeyFilter {
+ onPressed: event.accepted = filterKeyPress(event.key, event.text)
+ }
+
+ InputContext.MouseHandler {
+ onPressed: {
+ if (cursor < 0 || cursor >= InputContext.preeditText.length)
+ InputContext.commit()
+ }
+ }
+
+ model: XmlListModel {
+ id: suggestionModel
+
+ query: "/query/results/s:suggestion"
+ namespaceDeclarations: "declare namespace s=\"http://www.inktomi.com/\";"
+ source: InputContext.preeditText.length > 4 ? "http://query.yahooapis.com/v1/public/yql?q=select * from search.spelling where query=\"" + InputContext.preeditText + "\"" : ""
+
+ XmlRole { name: "suggestion"; query: "string()" }
+ }
+
+ delegate: Rectangle {
+ radius: 2
+ color: "lightsteelblue"
+
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ width: suggestionText.implicitWidth + 2
+ height: suggestionText.implicitHeight + 2
+
+ Text {
+ id: suggestionText
+
+ font: InputContext.font
+ text: suggestion
+
+ anchors.fill: parent
+ anchors.margins: 1
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: InputContext.commit(suggestion)
+ }
+ }
+}
diff --git a/examples/declarative/inputmethods/spellcheck/spellcheck.qml b/examples/declarative/inputmethods/spellcheck/spellcheck.qml
new file mode 100644
index 0000000000..57e81451a6
--- /dev/null
+++ b/examples/declarative/inputmethods/spellcheck/spellcheck.qml
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.inputcontext 1.0 as InputContext
+
+Item {
+ width: 360
+ height: 240
+
+ function filterKeyPress(key, text)
+ {
+ switch (key) {
+ case Qt.Key_Enter:
+ case Qt.Key_Return:
+ case Qt.Key_Space:
+ case Qt.Key_Tab:
+ if (InputContext.preeditText != "")
+ InputContext.commit();
+ break;
+ case Qt.Key_Backspace:
+ if (InputContext.preeditText != "") {
+ InputContext.preeditText = InputContext.preeditText.substr(0, InputContext.preeditText.length - 1);
+ return true;
+ }
+ break;
+ default:
+ if (text != "") {
+ InputContext.preeditText += text
+ return true;
+ } else if (InputContext.preeditText != "") {
+ InputContext.commit();
+ }
+ break;
+ }
+ return false;
+ }
+
+ Rectangle {
+ anchors.left: parent.left; anchors.top: parent.top; anchors.right: parent.right;
+ anchors.bottom: keyboard.top
+ anchors.margins: 2
+
+ border.width: 1
+ radius: 2
+
+ TextEdit {
+ id: textEdit
+
+ wrapMode: TextEdit.WordWrap
+
+ anchors.fill: parent
+ anchors.margins: 2
+ }
+
+ MouseArea {
+ anchors.fill: textEdit
+
+ onPressed: {
+ mouse.accepted = false
+ var position = textEdit.positionAt(mouse.x, mouse.y);
+ if (position != textEdit.cursorPosition) {
+ InputContext.commit()
+ textEdit.cursorPosition = textEdit.positionAt(mouse.x, mouse.y)
+ textEdit.selectWord()
+ var word = textEdit.selectedText
+ if (word != "") {
+ InputContext.commit("");
+ InputContext.preeditText = word;
+ }
+ }
+ }
+ }
+ }
+
+ WordSuggestions {}
+
+ Keyboard {
+ id: keyboard
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ y: parent.height
+
+ states: [
+ State {
+ name: "visible"
+ PropertyChanges { target: keyboard; y: parent.height - height }
+ when: InputContext.softwareInputPanelVisible
+ },
+ State {
+ name: "hidden"
+ PropertyChanges { target: keyboard; y: parent.height }
+ when: !InputContext.softwareInputPanelVisible
+ }
+ ]
+ transitions: Transition {
+ NumberAnimation { properties: "y"; easing.type: Easing.InOutQuad; duration: 100 }
+ }
+ }
+}
diff --git a/examples/declarative/painteditem/main.cpp b/examples/declarative/painteditem/main.cpp
new file mode 100644
index 0000000000..1308325ca3
--- /dev/null
+++ b/examples/declarative/painteditem/main.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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 <QtGui/qapplication.h>
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qsgview.h>
+#include <QtDeclarative/qsgpainteditem.h>
+
+class MyPaintItem : public QSGPaintedItem
+{
+ Q_OBJECT
+public:
+ virtual void paint(QPainter *p)
+ {
+ QRectF rect(0, 0, width(), height());
+ rect.adjust(10, 10, -10, -10);
+ p->setPen(QPen(Qt::black, 20));
+ p->setBrush(Qt::yellow);
+ p->drawEllipse(rect);
+ p->setPen(Qt::black);
+ p->setFont(QFont(QLatin1String("Times"), qRound(rect.height() / 2)));
+ p->drawText(rect, Qt::AlignCenter, QLatin1String(":-)"));
+ }
+};
+
+int main(int argc, char ** argv)
+{
+ QApplication app(argc, argv);
+
+ qmlRegisterType<MyPaintItem>("MyModule", 1, 0, "MyPaintItem");
+
+ QGLFormat f = QGLFormat::defaultFormat();
+ f.setSampleBuffers(true);
+ QSGView view(f);
+ view.setResizeMode(QSGView::SizeRootObjectToView);
+ view.setSource(QUrl::fromLocalFile("myfile.qml"));
+ view.show();
+ view.raise();
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/examples/declarative/painteditem/myfile.qml b/examples/declarative/painteditem/myfile.qml
new file mode 100644
index 0000000000..bc4bd2664b
--- /dev/null
+++ b/examples/declarative/painteditem/myfile.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import MyModule 1.0
+
+Rectangle {
+ width: 480
+ height: 480
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "#00249a" }
+ GradientStop { position: 0.7; color: "#ffd94f" }
+ GradientStop { position: 1.0; color: "#ffa322" }
+ }
+ MyPaintItem {
+ anchors.fill: parent
+ anchors.margins: 10
+ smooth: true
+ }
+}
diff --git a/examples/declarative/painteditem/painteditem.pro b/examples/declarative/painteditem/painteditem.pro
new file mode 100644
index 0000000000..5d7b9df074
--- /dev/null
+++ b/examples/declarative/painteditem/painteditem.pro
@@ -0,0 +1,14 @@
+TEMPLATE = app
+TARGET = painteditem
+
+QT += declarative
+
+macx: CONFIG -= app_bundle
+
+SOURCES += main.cpp
+
+CONFIG += console
+
+symbian {
+ TARGET.EPOCHEAPSIZE = 0x20000 0x5000000
+}
diff --git a/examples/declarative/particles/allsmiles/content/particle.png b/examples/declarative/particles/allsmiles/content/particle.png
new file mode 100644
index 0000000000..5c83896d22
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/particle.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/singlesmile.png b/examples/declarative/particles/allsmiles/content/singlesmile.png
new file mode 100644
index 0000000000..4087fa6b7f
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/singlesmile.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/sizeInOut.png b/examples/declarative/particles/allsmiles/content/sizeInOut.png
new file mode 100644
index 0000000000..0a306ea21a
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/sizeInOut.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/smileMask.png b/examples/declarative/particles/allsmiles/content/smileMask.png
new file mode 100644
index 0000000000..65a0143e9e
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/smileMask.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/squarefacesprite.png b/examples/declarative/particles/allsmiles/content/squarefacesprite.png
new file mode 100644
index 0000000000..f9a5d5fcce
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/squarefacesprite.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/squarefacesprite2.png b/examples/declarative/particles/allsmiles/content/squarefacesprite2.png
new file mode 100644
index 0000000000..7106a520a4
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/squarefacesprite2.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/squarefacesprite3.png b/examples/declarative/particles/allsmiles/content/squarefacesprite3.png
new file mode 100644
index 0000000000..f4e6f26856
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/squarefacesprite3.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/squarefacesprite4.png b/examples/declarative/particles/allsmiles/content/squarefacesprite4.png
new file mode 100644
index 0000000000..1e094eed4a
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/squarefacesprite4.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/squarefacesprite5.png b/examples/declarative/particles/allsmiles/content/squarefacesprite5.png
new file mode 100644
index 0000000000..1cfc5c7f8c
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/squarefacesprite5.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/squarefacesprite6.png b/examples/declarative/particles/allsmiles/content/squarefacesprite6.png
new file mode 100644
index 0000000000..b040139a9e
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/squarefacesprite6.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/squarefacesprite7.png b/examples/declarative/particles/allsmiles/content/squarefacesprite7.png
new file mode 100644
index 0000000000..b1e5e4e339
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/squarefacesprite7.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/squarefacespriteX.png b/examples/declarative/particles/allsmiles/content/squarefacespriteX.png
new file mode 100644
index 0000000000..93a0181dd0
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/squarefacespriteX.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/content/squarefacespriteXX.png b/examples/declarative/particles/allsmiles/content/squarefacespriteXX.png
new file mode 100644
index 0000000000..3159efe246
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/content/squarefacespriteXX.png
Binary files differ
diff --git a/examples/declarative/particles/allsmiles/smile.qml b/examples/declarative/particles/allsmiles/smile.qml
new file mode 100644
index 0000000000..e37e8fa98e
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/smile.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ color: "white"
+ width: 310
+ height: 300
+ ParticleSystem{ id: sys }
+ Picture{
+ system: sys
+ anchors.fill: parent
+ image: "content/singlesmile.png"
+ onceOff: true
+ }
+ ColoredParticle{
+ system: sys
+ image: "content/particle.png"
+ color: "black"
+ alpha: 0.4
+ sizeTable: "content/sizeInOut.png"
+ }
+ TrailEmitter{
+ id: emitter
+ system: sys
+ emitting: false
+ particleDuration: 4000
+ maxParticles: 1200
+ anchors.fill: parent
+ particleSize: 32
+ speed: PointVector{ xVariation: 12; yVariation: 12 }
+ }
+ MouseArea{
+ anchors.fill: parent
+ onClicked: emitter.burst(1200);
+ }
+}
+
diff --git a/examples/declarative/particles/allsmiles/smilefactory.qml b/examples/declarative/particles/allsmiles/smilefactory.qml
new file mode 100644
index 0000000000..1b43adb1da
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/smilefactory.qml
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ color: "goldenrod"
+ width: 400
+ height: 400
+ ParticleSystem{id:sys}
+ DeformableParticle{
+ system: sys
+ particles: ["goingLeft", "goingRight"]
+ image: "content/singlesmile.png"
+ rotation: 90
+ autoRotation: true
+ }
+ DeformableParticle{
+ system: sys
+ particles: ["goingDown"]
+ image: "content/squarefacespriteXX.png"
+ rotation: 180
+ yVector: PointVector{ y: 0.5; yVariation: 0.25; xVariation: 0.25; }
+ }
+ Timer{
+ running: true
+ repeat: false
+ interval: 100
+ onTriggered: emitA.emitting = true;
+ }
+ Timer{
+ running: true
+ repeat: false
+ interval: 4200
+ onTriggered: emitB.emitting = true;
+ }
+ Timer{
+ running: true
+ repeat: false
+ interval: 8400
+ onTriggered: emitC.emitting = true;
+ }
+ TrailEmitter{
+ id: emitA
+ x: 0
+ y: 120
+ system: sys
+ emitting: false
+ particle: "goingRight"
+ speed: PointVector{ x: 100 }
+ particleDuration: 4000
+ particlesPerSecond: 2
+ particleSize: 32
+ }
+ TrailEmitter{
+ id: emitB
+ x: 400
+ y: 240
+ system: sys
+ emitting: false
+ particle: "goingLeft"
+ speed: PointVector{ x: -100 }
+ particleDuration: 4000
+ particlesPerSecond: 2
+ particleSize: 32
+ }
+ TrailEmitter{
+ id: emitC
+ x: 0
+ y: 360
+ system: sys
+ emitting: false
+ particle: "goingDown"
+ speed: PointVector{ x: 100 }
+ particleDuration: 4000
+ particlesPerSecond: 2
+ particleSize: 32
+ }
+}
diff --git a/examples/declarative/particles/allsmiles/spriteparticles.qml b/examples/declarative/particles/allsmiles/spriteparticles.qml
new file mode 100644
index 0000000000..4bcb7081b8
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/spriteparticles.qml
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ color: "goldenrod"
+ width: 400
+ height: 400
+ ColoredParticle{
+ id: test
+ particles: ["Test"]
+ image: "content/particle.png"
+ system: sys
+ z: 2
+ anchors.fill: parent
+ color: "#336666CC"
+ colorVariation: 0.0
+ }
+ SpriteParticle{
+ id: single
+ particles: ["Face"]
+ system: sys
+ z: 2
+ anchors.fill: parent
+ Sprite{
+ source: "content/squarefacesprite.png"
+ frames: 6
+ duration: 120
+ }
+ }
+ Mask{
+ id: mask
+ source: "content/smileMask.png"
+ }
+ TrailEmitter{
+ system: sys
+ particle: "Test"
+ anchors.fill: parent
+ id: particles2
+ particlesPerSecond: 6000
+ particleDuration: 720
+ emitting: true
+ particleSize: 10
+ shape: mask
+ }
+ TrailEmitter{
+ system: sys
+ particle: "Face"
+ anchors.fill: parent
+ id: particles
+ particlesPerSecond: 60
+ particleDuration: 1440
+ emitting: true
+ speed: PointVector{xVariation: 10; yVariation: 10;}
+ particleSize: 30
+ particleSizeVariation: 10
+ shape: mask
+ }
+ ParticleSystem{
+ id: sys
+ anchors.fill: parent
+ }
+
+}
diff --git a/examples/declarative/particles/allsmiles/spritestateparticles.qml b/examples/declarative/particles/allsmiles/spritestateparticles.qml
new file mode 100644
index 0000000000..6a61487a89
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/spritestateparticles.qml
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ color: "goldenrod"
+ width: 800
+ height: 800
+ id: root
+ SpriteImage{
+ sprites: [Sprite{
+ name: "happy"
+ source: "content/squarefacesprite2.png"
+ frames: 6
+ duration: 120
+ to: {"silly": 0.4, "sad": 0.2, "cyclops":0.1, "boggled":0.3, "dying":0.0}
+ }, Sprite{
+ name: "silly"
+ source: "content/squarefacesprite.png"
+ frames: 6
+ duration: 120
+ to: {"love": 0.4, "happy": 0.1, "evil": 0.2, "cyclops":0.1, "boggled":0.2}
+ }, Sprite{
+ name: "sad"
+ source: "content/squarefacesprite3.png"
+ frames: 6
+ duration: 120
+ to: {"love" : 0.2, "evil": 0.2, "silly": 0.2, "cyclops":0.2, "boggled":0.2}
+ }, Sprite{
+ name: "cyclops"
+ source: "content/squarefacesprite4.png"
+ frames: 6
+ duration: 120
+ to: {"love": 0.1, "evil": 0.1, "silly":0.1, "boggled":0.1, "cyclops" : 1.0}
+ }, Sprite{
+ name: "evil"
+ source: "content/squarefacesprite5.png"
+ frames: 6
+ duration: 120
+ to: {"happy": 1.0}
+ }, Sprite{
+ name: "love"
+ source: "content/squarefacesprite6.png"
+ frames: 6
+ duration: 120
+ to: {"sad": 0.6, "evil":0.4, "boggled":0.2}
+ }, Sprite{
+ name: "boggled"
+ source: "content/squarefacesprite7.png"
+ frames: 6
+ duration: 120
+ to: {"love" : 0.2, "evil": 0.2, "silly": 0.2, "cyclops":0.1, "sad":0.2}
+ }, Sprite{
+ name: "dying"
+ source: "content/squarefacespriteX.png"
+ frames: 4
+ duration: 120
+ to: {"dead":1.0}
+ }, Sprite{
+ name: "dead"
+ source: "content/squarefacespriteXX.png"
+ frames: 1
+ duration: 10000
+ }]
+
+ width: 100
+ height: 100
+ x: 20
+ y: 20
+ z:4
+ }
+ ParticleSystem{ id: sys }
+ SpriteParticle{
+ anchors.fill: parent
+ id: particles
+ system: sys
+ sprites: [Sprite{
+ name: "happy"
+ source: "content/squarefacesprite2.png"
+ frames: 6
+ duration: 120
+ to: {"silly": 0.4, "sad": 0.2, "cyclops":0.1, "boggled":0.3, "dying":0.0}
+ }, Sprite{
+ name: "silly"
+ source: "content/squarefacesprite.png"
+ frames: 6
+ duration: 120
+ to: {"love": 0.4, "happy": 0.1, "evil": 0.2, "cyclops":0.1, "boggled":0.2}
+ }, Sprite{
+ name: "sad"
+ source: "content/squarefacesprite3.png"
+ frames: 6
+ duration: 120
+ to: {"love" : 0.2, "evil": 0.2, "silly": 0.2, "cyclops":0.2, "boggled":0.2}
+ }, Sprite{
+ name: "cyclops"
+ source: "content/squarefacesprite4.png"
+ frames: 6
+ duration: 120
+ to: {"love": 0.1, "evil": 0.1, "silly":0.1, "boggled":0.1, "cyclops" : 1.0}
+ }, Sprite{
+ name: "evil"
+ source: "content/squarefacesprite5.png"
+ frames: 6
+ duration: 120
+ to: {"happy": 1.0}
+ }, Sprite{
+ name: "love"
+ source: "content/squarefacesprite6.png"
+ frames: 6
+ duration: 120
+ to: {"sad": 0.6, "evil":0.4, "boggled":0.2}
+ }, Sprite{
+ name: "boggled"
+ source: "content/squarefacesprite7.png"
+ frames: 6
+ duration: 120
+ to: {"love" : 0.2, "evil": 0.2, "silly": 0.2, "cyclops":0.1, "sad":0.2}
+ }, Sprite{
+ name: "dying"
+ source: "content/squarefacespriteX.png"
+ frames: 4
+ duration: 120
+ to: {"dead":1.0}
+ }, Sprite{
+ name: "dead"
+ source: "content/squarefacespriteXX.png"
+ frames: 1
+ duration: 10000
+ }]
+ }
+ TrailEmitter{
+ system: sys
+ particlesPerSecond: 16
+ particleDuration: 10000
+ emitting: true
+ speed: AngleVector{angle: 90; magnitude: 60; angleVariation: 5}
+ acceleration: PointVector{ y: 10 }
+ particleSize: 30
+ particleSizeVariation: 10
+ width: parent.width
+ height: 100
+ }
+ SpriteGoal{
+ system: sys
+ width: root.width;
+ height: root.height/2;
+ y: root.height/2;
+ goalState:"dead"
+ }
+}
diff --git a/examples/declarative/particles/allsmiles/spritevariedparticles.qml b/examples/declarative/particles/allsmiles/spritevariedparticles.qml
new file mode 100644
index 0000000000..c1b773093f
--- /dev/null
+++ b/examples/declarative/particles/allsmiles/spritevariedparticles.qml
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ color: "goldenrod"
+ width: 800
+ height: 800
+ ParticleSystem{ id: sys }
+ SpriteParticle{
+ system: sys
+ anchors.fill: parent
+ sprites: [Sprite{
+ name: "initial"
+ source: "content/squarefacesprite.png"
+ frames: 6
+ duration: 0
+ to: {"happy":0.2, "silly":0.2, "sad":0.2, "cyclops":0.1, "evil":0.1, "love":0.1, "boggled":0.1}
+ }, Sprite{
+ name: "silly"
+ source: "content/squarefacesprite.png"
+ frames: 6
+ duration: 120
+ }, Sprite{
+ name: "happy"
+ source: "content/squarefacesprite2.png"
+ frames: 6
+ duration: 120
+ }, Sprite{
+ name: "sad"
+ source: "content/squarefacesprite3.png"
+ frames: 6
+ duration: 120
+ }, Sprite{
+ name: "cyclops"
+ source: "content/squarefacesprite4.png"
+ frames: 6
+ duration: 120
+ }, Sprite{
+ name: "evil"
+ source: "content/squarefacesprite5.png"
+ frames: 6
+ duration: 120
+ }, Sprite{
+ name: "love"
+ source: "content/squarefacesprite6.png"
+ frames: 6
+ duration: 120
+ }, Sprite{
+ name: "boggled"
+ source: "content/squarefacesprite7.png"
+ frames: 6
+ duration: 120
+ }]
+ }
+ TrailEmitter{
+ id: particleEmitter
+ system: sys
+ width: parent.width
+ particlesPerSecond: 16
+ particleDuration: 8000
+ emitting: true
+ speed: AngleVector{angle: 90; magnitude: 300; magnitudeVariation: 100; angleVariation: 5}
+ acceleration: PointVector{ y: 10 }
+ particleSize: 30
+ particleSizeVariation: 10
+ }
+ Binding{
+ target: particleEmitter
+ property: "y"
+ value: ma.mouseY
+ when: ma.mouseX !=0 || ma.mouseY!=0
+ }
+ MouseArea{
+ id: ma
+ anchors.fill: parent
+ }
+}
diff --git a/examples/declarative/particles/asteroid/asteroid.qml b/examples/declarative/particles/asteroid/asteroid.qml
new file mode 100644
index 0000000000..b5b4f672c2
--- /dev/null
+++ b/examples/declarative/particles/asteroid/asteroid.qml
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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 Qt.labs.particles 2.0
+import Qt.labs.particles 2.0 as Qlp
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 360
+ height: 540
+ MouseArea{
+ id: ma
+ anchors.fill: parent
+ }
+
+ ParticleSystem { id: sys }
+ Image {
+ source: "content/finalfrontier.png"
+ transformOrigin: Item.Center
+ anchors.centerIn: parent
+ smooth: true
+ NumberAnimation on rotation {
+ from: 0
+ to: 360
+ duration: 200000
+ loops: Animation.Infinite
+ }
+
+ }
+ ColoredParticle {
+ system: sys
+ particles: ["starfield"]
+ image: "content/star.png"
+ colorVariation: 0.3
+ color: "white"
+ }
+ TrailEmitter {
+ id: starField
+ system: sys
+ particle: "starfield"
+
+ particlesPerSecond: 80
+ particleDuration: 2500
+
+ anchors.centerIn: parent
+
+ //acceleration: AngleVector{angleVariation: 360; magnitude: 200}//Is this a better effect, more consistent speed?
+ acceleration: PointVector{ xVariation: 200; yVariation: 200; }
+
+ particleSize: 0
+ particleEndSize: 80
+ particleSizeVariation: 10
+ }
+ TrailEmitter{
+ system: sys
+ particle: "meteor"
+ particlesPerSecond: 12
+ particleDuration: 5000
+ emitting: true
+ acceleration: PointVector{ xVariation: 80; yVariation: 80; }
+ particleSize: 15
+ particleEndSize: 300
+ anchors.centerIn: parent
+ }
+ SpriteParticle{
+ system: sys
+ particles: ["meteor"]
+ sprites:[Sprite{
+ id: spinState
+ name: "spinning"
+ source: "content/meteor.png"
+ frames: 35
+ duration: 40
+ speedModifiesDuration: -0.1
+ to: {"explode":0, "spinning":1}
+ },Sprite{
+ name: "explode"
+ source: "content/_explo.png"
+ frames: 22
+ duration: 40
+ speedModifiesDuration: -0.1
+ to: {"nullFrame":1}
+ },Sprite{//Not sure if this is needed, but seemed easiest
+ name: "nullFrame"
+ source: "content/nullRock.png"
+ frames: 1
+ duration: 1000
+ }
+ ]
+ }
+ SpriteGoal{
+ particles: ["meteor"]
+ system: sys
+ goalState: "explode"
+ jump: true
+ anchors.centerIn: holder//A bug in affectors currently isn't compensating for relative x,y. when that's fixed this can just anchors.fill: rocketShip
+ width: 60
+ height: 60
+ }
+ Image {
+ id: rocketShip
+ source: "content/rocket.png"
+ smooth: true
+ anchors.centerIn: holder
+ rotation: (circle.percent+0.25) * 360
+ z: 2
+ }
+ Item {
+ id: holder
+ x: circle.x - Math.sin(circle.percent * 6.28316530714)*200
+ y: circle.y + Math.cos(circle.percent * 6.28316530714)*200
+ z: 1
+ }
+
+ Item {
+ id: circle
+ x: root.width / 1.2
+ y: root.height / 1.7
+ property real percent: 0
+
+ SequentialAnimation on percent {
+ id: circleAnim1
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ duration: 4000
+ from: 1
+ to: 0
+ }
+
+ }
+ }
+ ColoredParticle{
+ z:0
+ system: sys
+ particles: ["exhaust"]
+ image: "content/particle4.png"
+
+ color: "orange"
+ SequentialAnimation on color {
+ loops: Animation.Infinite
+ ColorAnimation {
+ from: "red"
+ to: "cyan"
+ duration: 1000
+ }
+ ColorAnimation {
+ from: "cyan"
+ to: "red"
+ duration: 1000
+ }
+ }
+
+ colorVariation: 0.2
+ }
+ TrailEmitter{
+ id: trailsNormal2
+ system: sys
+ particle: "exhaust"
+
+ particlesPerSecond: 300
+ particleDuration: 500
+
+ y: holder.y
+ x: holder.x
+
+ speed: PointVector{ xVariation: 40; yVariation: 40; }
+ speedFromMovement: 16
+
+ acceleration: PointVector{ xVariation: 10; yVariation: 10; }
+
+ particleSize: 4
+ particleSizeVariation: 4
+ }
+}
diff --git a/examples/declarative/particles/asteroid/blackhole.qml b/examples/declarative/particles/asteroid/blackhole.qml
new file mode 100644
index 0000000000..68d5835880
--- /dev/null
+++ b/examples/declarative/particles/asteroid/blackhole.qml
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ id: root
+ width: 360
+ height: 540
+ color: "black"
+ property bool spacePressed: false
+ focus: true
+ Image{
+ source: "content/finalfrontier.png"
+ anchors.centerIn:parent
+ }
+ Keys.onPressed: {
+ if (event.key == Qt.Key_Space) {
+ spacePressed = true;
+ event.accepted = true;
+ }
+ }
+ Keys.onReleased: {
+ if (event.key == Qt.Key_Space) {
+ spacePressed = false;
+ event.accepted = true;
+ }
+ }
+
+ TrailEmitter{
+ particle: "stars"
+ system: particles
+ particlesPerSecond: 40
+ particleDuration: 4000
+ emitting: true
+ particleSize: 30
+ particleSizeVariation: 10
+ speed: PointVector{ x: 220; xVariation: 40 }
+ height: parent.height
+ }
+ TrailEmitter{
+ particle: "roids"
+ system: particles
+ particlesPerSecond: 10
+ particleDuration: 4000
+ emitting: true
+ particleSize: 30
+ particleSizeVariation: 10
+ speed: PointVector{ x: 220; xVariation: 40 }
+ height: parent.height
+ }
+ ParticleSystem{
+ id: particles
+ anchors.fill: parent
+ }
+ ColoredParticle{
+ id: stars
+ particles: ["stars"]
+ system: particles
+ image: "content/star.png"
+ color: "white"
+ colorVariation: 0.1
+ }
+ SpriteParticle{
+ id: roids
+ particles: ["roids"]
+ system: particles
+ sprites: Sprite{
+ id: spinState
+ name: "spinning"
+ source: "content/meteor.png"
+ frames: 35
+ duration: 60
+ speedModifiesDuration: -0.1
+ }
+ }
+ ColoredParticle{
+ id: shot
+ particles: ["shot"]
+ system: particles
+ image: "content/star.png"
+
+ color: "#0FF06600"
+ colorVariation: 0.3
+ }
+ ColoredParticle{
+ id: engine
+ particles: ["engine"]
+ system: particles
+ image: "content/particle4.png"
+
+ color: "orange"
+ SequentialAnimation on color {
+ loops: Animation.Infinite
+ ColorAnimation {
+ from: "red"
+ to: "cyan"
+ duration: 1000
+ }
+ ColorAnimation {
+ from: "cyan"
+ to: "red"
+ duration: 1000
+ }
+ }
+
+ colorVariation: 0.2
+ }
+ GravitationalSingularity{
+ id: gs; x: root.width/2; y: root.height/2; strength: 4000000;
+ system: particles
+ }
+ Kill{
+ system: particles
+ x: gs.x - 8;
+ y: gs.y - 8;
+ width: 16
+ height: 16
+ }
+ Image{
+ source:"content/rocket2.png"
+ id: ship
+ width: 45
+ height: 22
+ MouseArea{
+ id: ma
+ anchors.fill: parent;
+ drag.axis: Drag.XandYAxis
+ drag.target: ship
+ }
+ TrailEmitter{
+ particle: "engine"
+ system: particles
+ particlesPerSecond: 200
+ particleDuration: 1000
+ emitting: true
+ particleSize: 10
+ particleEndSize: 4
+ particleSizeVariation: 4
+ speed: PointVector{ x: -128; xVariation: 32 }
+ height: parent.height
+ width: 20
+ }
+ TrailEmitter{
+ particle: "shot"
+ system: particles
+ particlesPerSecond: 32
+ particleDuration: 2000
+ emitting: spacePressed
+ particleSize: 40
+ speed: PointVector{ x: 256; }
+ x: parent.width
+ y: parent.height/2
+ }
+ }
+ Text{
+ color: "white"
+ anchors.bottom: parent.bottom
+ text:"Drag the ship, Spacebar to fire."
+ }
+}
+
diff --git a/examples/declarative/particles/asteroid/content/_explo.png b/examples/declarative/particles/asteroid/content/_explo.png
new file mode 100644
index 0000000000..4297245d49
--- /dev/null
+++ b/examples/declarative/particles/asteroid/content/_explo.png
Binary files differ
diff --git a/examples/declarative/particles/asteroid/content/finalfrontier.png b/examples/declarative/particles/asteroid/content/finalfrontier.png
new file mode 100644
index 0000000000..2ba1815230
--- /dev/null
+++ b/examples/declarative/particles/asteroid/content/finalfrontier.png
Binary files differ
diff --git a/examples/declarative/particles/asteroid/content/meteor.png b/examples/declarative/particles/asteroid/content/meteor.png
new file mode 100644
index 0000000000..e8c368aea7
--- /dev/null
+++ b/examples/declarative/particles/asteroid/content/meteor.png
Binary files differ
diff --git a/examples/declarative/particles/asteroid/content/meteor_explo.png b/examples/declarative/particles/asteroid/content/meteor_explo.png
new file mode 100644
index 0000000000..e659bfe2cf
--- /dev/null
+++ b/examples/declarative/particles/asteroid/content/meteor_explo.png
Binary files differ
diff --git a/examples/declarative/particles/asteroid/content/meteors.png b/examples/declarative/particles/asteroid/content/meteors.png
new file mode 100644
index 0000000000..bada8a1407
--- /dev/null
+++ b/examples/declarative/particles/asteroid/content/meteors.png
Binary files differ
diff --git a/examples/declarative/particles/asteroid/content/nullRock.png b/examples/declarative/particles/asteroid/content/nullRock.png
new file mode 100644
index 0000000000..4076327a1a
--- /dev/null
+++ b/examples/declarative/particles/asteroid/content/nullRock.png
Binary files differ
diff --git a/examples/declarative/particles/asteroid/content/particle4.png b/examples/declarative/particles/asteroid/content/particle4.png
new file mode 100644
index 0000000000..bc95b703c1
--- /dev/null
+++ b/examples/declarative/particles/asteroid/content/particle4.png
Binary files differ
diff --git a/examples/declarative/particles/asteroid/content/rocket.png b/examples/declarative/particles/asteroid/content/rocket.png
new file mode 100644
index 0000000000..a171610b03
--- /dev/null
+++ b/examples/declarative/particles/asteroid/content/rocket.png
Binary files differ
diff --git a/examples/declarative/particles/asteroid/content/rocket2.png b/examples/declarative/particles/asteroid/content/rocket2.png
new file mode 100644
index 0000000000..7110f8fdc6
--- /dev/null
+++ b/examples/declarative/particles/asteroid/content/rocket2.png
Binary files differ
diff --git a/examples/declarative/particles/asteroid/content/star.png b/examples/declarative/particles/asteroid/content/star.png
new file mode 100644
index 0000000000..0d592cfa87
--- /dev/null
+++ b/examples/declarative/particles/asteroid/content/star.png
Binary files differ
diff --git a/examples/declarative/particles/modelparticles/bubbles.qml b/examples/declarative/particles/modelparticles/bubbles.qml
new file mode 100644
index 0000000000..711d52d522
--- /dev/null
+++ b/examples/declarative/particles/modelparticles/bubbles.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+import "../../modelviews/listview/content" as OtherDemo
+import "content/script.js" as Script
+import "content"
+//Needs OtherDemo to be updated to QtQuick 2.0
+
+Item{
+ id: root
+ width: 400
+ height: 400
+ Rectangle{
+ anchors.fill: parent
+ color: "lightsteelblue"
+ }
+ ParticleSystem{
+ id: sys;
+ }
+ TrailEmitter{
+ system: sys
+ particle: "A"
+ width: parent.width/2
+ x: parent.width/4
+ y:parent.height
+ speed: PointVector{ y: -64; yVariation: 16 }
+ particlesPerSecond: 1
+ particleDuration: 8000
+ }
+ Drift{
+ system: sys
+ xDrift: 200
+ }
+ ModelParticle{
+ id: mp
+ z: 0
+ system: sys
+ particles: ["A"]
+ model: OtherDemo.RecipesModel{}
+ delegate: ExpandingDelegate{}
+ }
+}
diff --git a/examples/declarative/particles/modelparticles/content/Delegate.qml b/examples/declarative/particles/modelparticles/content/Delegate.qml
new file mode 100644
index 0000000000..ae1dffb63b
--- /dev/null
+++ b/examples/declarative/particles/modelparticles/content/Delegate.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+
+//![0]
+Package {
+ Text { id: listDelegate; width: 200; height: 25; text: 'Empty'; Package.name: 'list' }
+ Text { id: gridDelegate; width: 100; height: 50; text: 'Empty'; Package.name: 'grid' }
+
+ Rectangle {
+ id: wrapper
+ width: 200; height: 25
+ color: 'lightsteelblue'
+
+ Text { text: display; anchors.centerIn: parent }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (wrapper.state == 'inList')
+ wrapper.state = 'inGrid';
+ else
+ wrapper.state = 'inList';
+ }
+ }
+
+ state: 'inList'
+ states: [
+ State {
+ name: 'inList'
+ ParentChange { target: wrapper; parent: listDelegate }
+ },
+ State {
+ name: 'inGrid'
+ ParentChange {
+ target: wrapper; parent: gridDelegate
+ x: 0; y: 0; width: gridDelegate.width; height: gridDelegate.height
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ ParentAnimation {
+ NumberAnimation { properties: 'x,y,width,height'; duration: 300 }
+ }
+ }
+ ]
+ }
+}
+//![0]
diff --git a/examples/declarative/particles/modelparticles/content/Delegate2.qml b/examples/declarative/particles/modelparticles/content/Delegate2.qml
new file mode 100644
index 0000000000..a05fa348b9
--- /dev/null
+++ b/examples/declarative/particles/modelparticles/content/Delegate2.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+
+//![0]
+Package {
+ Item { id: gridDelegate; width: w; height: h; Package.name: 'grid' }
+ Item { id: particleDelegate; width: w; height: h; Package.name: 'particles'
+
+ Rectangle {
+ id: wrapper
+ width: w; height: h;
+ color: col
+ rotation: Math.random()*360
+ Behavior on rotation{RotationAnimation{}}
+
+ states: State{
+ name: "gridded"
+ when: root.inGrid
+ PropertyChanges{
+ target: wrapper
+ rotation: 0
+ }
+ ParentChange{
+ target: wrapper
+ parent: gridDelegate
+ x:0
+ y:0
+ }
+ }
+ transitions: [
+ Transition {
+ ParentAnimation {
+ NumberAnimation { properties: 'x,y,width,height'; duration: 300 }
+ }
+ }
+ ]
+ }
+ }
+}
+//![0]
diff --git a/examples/declarative/particles/modelparticles/content/ExpandingDelegate.qml b/examples/declarative/particles/modelparticles/content/ExpandingDelegate.qml
new file mode 100644
index 0000000000..e6fcb6dcf7
--- /dev/null
+++ b/examples/declarative/particles/modelparticles/content/ExpandingDelegate.qml
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import "../../../modelviews/listview/content"
+
+// This example illustrates expanding a list item to show a more detailed view.
+
+ // Delegate for the recipes. This delegate has two modes:
+ // 1. List mode (default), which just shows the picture and title of the recipe.
+ // 2. Details mode, which also shows the ingredients and method.
+ Component {
+ id: recipeDelegate
+
+ Item {
+ id: recipe
+
+ // Create a property to contain the visibility of the details.
+ // We can bind multiple element's opacity to this one property,
+ // rather than having a "PropertyChanges" line for each element we
+ // want to fade.
+ property real detailsOpacity : 0
+
+ //this bit changed for aesthetics
+ width: 70
+ height: 70
+ // A simple rounded rectangle for the background
+ Rectangle {
+ id: background
+ x: 2; y: 2; width: parent.width - x*2; height: parent.height - y*2
+ color: "ivory"
+ border.color: "orange"
+ radius: 5
+ }
+ Image{
+ anchors.fill:parent
+ anchors.margins: -32
+ source: "bubble.png"
+ }
+
+
+ // This mouse region covers the entire delegate.
+ // When clicked it changes mode to 'Details'. If we are already
+ // in Details mode, then no change will happen.
+ MouseArea {
+ anchors.fill: parent
+ onClicked: recipe.state = 'Details';
+ }
+
+ // Lay out the page: picture, title and ingredients at the top, and method at the
+ // bottom. Note that elements that should not be visible in the list
+ // mode have their opacity set to recipe.detailsOpacity.
+ Row {
+ id: topLayout
+ x: 10; y: 10; height: recipeImage.height; width: parent.width
+ spacing: 10
+
+ Image {
+ id: recipeImage
+ width: 50; height: 50
+ source: "../../modelviews/listview/" + picture
+ }
+
+ Column {
+ width: background.width - recipeImage.width - 20; height: recipeImage.height
+ spacing: 5
+
+ Text {
+ text: title
+ font.bold: true; font.pointSize: 16
+ }
+
+ Text {
+ text: "Ingredients"
+ font.pointSize: 12; font.bold: true
+ opacity: recipe.detailsOpacity
+ }
+
+ Text {
+ text: ingredients
+ wrapMode: Text.WordWrap
+ width: parent.width
+ opacity: recipe.detailsOpacity
+ }
+ }
+ }
+
+ Item {
+ id: details
+ x: 10; width: parent.width - 20
+ anchors { top: topLayout.bottom; topMargin: 10; bottom: parent.bottom; bottomMargin: 10 }
+ opacity: recipe.detailsOpacity
+
+ Text {
+ id: methodTitle
+ anchors.top: parent.top
+ text: "Method"
+ font.pointSize: 12; font.bold: true
+ }
+
+ Flickable {
+ id: flick
+ width: parent.width
+ anchors { top: methodTitle.bottom; bottom: parent.bottom }
+ contentHeight: methodText.height
+ clip: true
+
+ Text { id: methodText; text: method; wrapMode: Text.WordWrap; width: details.width }
+ }
+
+ Image {
+ anchors { right: flick.right; top: flick.top }
+ source: "../../modelviews/listview/" + "content/pics/moreUp.png"
+ opacity: flick.atYBeginning ? 0 : 1
+ }
+
+ Image {
+ anchors { right: flick.right; bottom: flick.bottom }
+ source: "../../modelviews/listview/" + "content/pics/moreDown.png"
+ opacity: flick.atYEnd ? 0 : 1
+ }
+ }
+
+ // A button to close the detailed view, i.e. set the state back to default ('').
+ TextButton {
+ y: 10
+ anchors { right: background.right; rightMargin: 10 }
+ opacity: recipe.detailsOpacity
+ text: "Close"
+
+ onClicked: recipe.state = '';
+ }
+
+ states: State {
+ name: "Details"
+
+ PropertyChanges { target: background; color: "white" }
+ PropertyChanges { target: recipeImage; width: 130; height: 130 } // Make picture bigger
+ PropertyChanges { target: recipe; detailsOpacity: 1; x: 0; opacity: 1 } // Make details visible
+ PropertyChanges { target: recipe; height: root.height; width: root.height; x:0; y:0; z:100} // Fill the entire list area with the detailed view
+
+ // Move the list so that this item is at the top.
+ //PropertyChanges { target: recipe.ListView.view; explicit: true; contentY: recipe.y }
+
+ // Disallow flicking while we're in detailed view
+ //PropertyChanges { target: recipe.ListView.view; interactive: false }
+ }
+
+ transitions: Transition {
+ //The only strictly necessary particle specific lines
+ to: "Details"
+ reversible: true
+ ScriptAction{script:{
+ if(state == "Details")
+ mp.freeze(index);
+ else
+ mp.unfreeze(index);
+ }
+ }
+ // Make the state changes smooth
+ ParallelAnimation {
+ ColorAnimation { property: "color"; duration: 500 }
+ NumberAnimation { duration: 300; properties: "detailsOpacity,opacity,x,y,height,width" }
+ }
+ }
+ }
+ }
diff --git a/examples/declarative/particles/modelparticles/content/RssModel.qml b/examples/declarative/particles/modelparticles/content/RssModel.qml
new file mode 100644
index 0000000000..603a157de5
--- /dev/null
+++ b/examples/declarative/particles/modelparticles/content/RssModel.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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 1.0
+
+XmlListModel {
+ property string tags : ""
+
+ source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+tags+"&" : "")
+ query: "/feed/entry"
+ namespaceDeclarations: "declare default element namespace 'http://www.w3.org/2005/Atom';"
+
+ XmlRole { name: "title"; query: "title/string()" }
+ XmlRole { name: "content"; query: "content/string()" }
+ XmlRole { name: "hq"; query: "link[@rel='enclosure']/@href/string()" }
+}
diff --git a/examples/declarative/particles/modelparticles/content/bubble.png b/examples/declarative/particles/modelparticles/content/bubble.png
new file mode 100644
index 0000000000..c7f479e9e3
--- /dev/null
+++ b/examples/declarative/particles/modelparticles/content/bubble.png
Binary files differ
diff --git a/examples/declarative/particles/modelparticles/content/script.js b/examples/declarative/particles/modelparticles/content/script.js
new file mode 100644
index 0000000000..e8ef93a847
--- /dev/null
+++ b/examples/declarative/particles/modelparticles/content/script.js
@@ -0,0 +1,27 @@
+.pragma library
+
+function getWidth(string) {
+ return (string.match(/width=\"([0-9]+)\"/))[1]
+}
+
+function getHeight(string) {
+ return (string.match(/height=\"([0-9]+)\"/))[1]
+}
+
+function getImagePath(string) {
+ var pattern = /src=\"http:\/\/(\S+)\"/
+ return (string.match(pattern))[1]
+}
+
+function calculateScale(width, height, cellSize) {
+ var widthScale = (cellSize * 1.0) / width
+ var heightScale = (cellSize * 1.0) / height
+ var scale = 0
+
+ if (widthScale <= heightScale) {
+ scale = widthScale;
+ } else if (heightScale < widthScale) {
+ scale = heightScale;
+ }
+ return scale;
+}
diff --git a/examples/declarative/particles/modelparticles/gridsplosion.qml b/examples/declarative/particles/modelparticles/gridsplosion.qml
new file mode 100644
index 0000000000..a654124587
--- /dev/null
+++ b/examples/declarative/particles/modelparticles/gridsplosion.qml
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+import "content"
+
+Item{
+ id: root
+ width: 240
+ height: 240
+ property bool inGrid: false
+ ParticleSystem{ id: sys }
+ TrailEmitter{
+ system: sys
+ id: burster;
+ emitting: false
+ particlesPerSecond: 1000
+ particleDuration: 500
+ speed: PointVector{xVariation: 400; yVariation: 400}
+ anchors.centerIn: parent
+ Timer{
+ interval: 1000
+ running: true
+ repeat: false
+ onTriggered: burster.pulse(0.1);
+ }
+ Timer{
+ interval: 2000
+ running: true
+ repeat: false
+ onTriggered: {inGrid = true;}// sys.running = false;}
+ }
+ }
+ ColoredParticle{
+ system: sys
+ image: "../trails/content/particle.png"
+ color: "black"
+ colorVariation: 0.0
+ }
+ GridView{ id: grid; cellWidth: 40; cellHeight: 40
+ model: theModel.parts.grid
+ width: 120
+ height: 120
+ }
+ ModelParticle{
+ system: sys
+ model: theModel.parts.particles
+ }
+ Friction{
+ system: sys
+ factor: 1
+ }
+ Stasis{
+ system: sys
+ targetLife: 400
+ }
+ VisualDataModel{
+ id: theModel
+ delegate: Delegate2{}
+ model: ListModel{
+ ListElement{
+ w: 40
+ h: 20
+ col: "forestgreen"
+ }
+ ListElement{
+ w: 20
+ h: 40
+ col: "salmon"
+ }
+ ListElement{
+ w: 20
+ h: 20
+ col: "lightsteelblue"
+ }
+ ListElement{
+ w: 40
+ h: 40
+ col: "goldenrod"
+ }
+ ListElement{
+ w: 40
+ h: 20
+ col: "forestgreen"
+ }
+ ListElement{
+ w: 20
+ h: 40
+ col: "salmon"
+ }
+ ListElement{
+ w: 20
+ h: 20
+ col: "lightsteelblue"
+ }
+ ListElement{
+ w: 40
+ h: 40
+ col: "goldenrod"
+ }
+ ListElement{
+ w: 0
+ h: 0
+ col: "white"//Hack because add isn't working well with old stuff
+ }
+ }
+ }
+}
diff --git a/examples/declarative/particles/modelparticles/package.qml b/examples/declarative/particles/modelparticles/package.qml
new file mode 100644
index 0000000000..402cdea84a
--- /dev/null
+++ b/examples/declarative/particles/modelparticles/package.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+import "content"
+
+Rectangle {
+ color: "white"
+ width: 400
+ height: 200
+
+ ListModel {
+ id: myModel
+ ListElement { display: "One" }
+ ListElement { display: "Two" }
+ ListElement { display: "Three" }
+ ListElement { display: "Four" }
+ ListElement { display: "Five" }
+ ListElement { display: "Six" }
+ ListElement { display: "Seven" }
+ ListElement { display: "Eight" }
+ }
+ //![0]
+ VisualDataModel {
+ id: visualModel
+ delegate: Delegate {}
+ model: myModel
+ }
+
+ ListView {
+ width: 200; height:200
+ model: visualModel.parts.list
+ }
+ ModelParticle{
+ x: 200; width: 200; height:200
+ model: visualModel.parts.grid
+ system: sys
+ clip: true;
+ }
+ //![0]
+ ParticleSystem{
+ id: sys
+ anchors.fill: parent
+ }
+ TrailEmitter{
+ system: sys
+ width: 100
+ x: 50
+ speed: PointVector{ y: 40 }
+ particleDuration: 5000
+ particlesPerSecond: 1.6
+ }
+}
diff --git a/examples/declarative/particles/modelparticles/stream.qml b/examples/declarative/particles/modelparticles/stream.qml
new file mode 100644
index 0000000000..b67d6c42af
--- /dev/null
+++ b/examples/declarative/particles/modelparticles/stream.qml
@@ -0,0 +1,280 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+import "content/script.js" as Script
+import "content"
+
+Item{
+ id: root
+ width: 640
+ height: 480
+ Rectangle{
+ anchors.fill: parent
+ color: "black"
+ z: -1
+ }
+ Item{
+ id: loading
+ Behavior on opacity{NumberAnimation{}}
+ anchors.fill: parent
+ Text{
+ anchors.centerIn: parent
+ text: "Loading"
+ color: "white"
+ }
+ }
+ ParticleSystem{
+ id: sys;
+ running: true
+ overwrite: false
+ startTime: 12000//Doesn't actually work with the loading time though...
+ }
+ TrailEmitter{
+ id: emitter
+ system: sys
+ height: parent.height - 132/2
+ x: -132/2
+ y: 132/2
+ speed: PointVector{ x: 32; xVariation: 8 }
+ particlesPerSecond: 0.5
+ particleDuration: 120000 //TODO: A -1 or something which does 'infinite'? (but need disable fade first)
+ particle: "photos"
+ }
+ Kill{
+ system: sys
+ x: parent.width + 132/2
+ height: parent.height
+ width: 1000
+ }
+ ColoredParticle{
+ system: sys
+ particles: ["fireworks"]
+ image: "../trails/content/star.png"
+ color: "lightsteelblue"
+ alpha: 0
+ colorVariation: 0
+ z: 1000
+ }
+ ModelParticle{
+ id: mp
+ z: 0
+ system: sys
+ fade: false
+ particles: ["photos"]
+ }
+ Component{
+ id: alertDelegate
+ Rectangle{
+ width: 132
+ height: 132
+ NumberAnimation on scale{
+ running: true
+ loops: 1
+ from: 0.2
+ to: 1
+ }
+ Image{
+ source: "../asteroid/content/rocket.png"
+ anchors.centerIn: parent
+ }
+ Text{
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "A new ship has arrived!"
+ }
+ }
+ }
+ property Item alertItem;
+ function alert(){
+ resetter.active = false
+ force.active = true;
+ alertItem = alertDelegate.createObject(root);
+ alertItem.x = root.width/2 - alertItem.width/2
+ alertItem.y = root.height/2 - alertItem.height/2
+ spawnFireworks.pulse(0.2);
+ stopAlert.start();
+ }
+ focus: true
+ Keys.onSpacePressed: alert();
+ Timer{
+ id: stopAlert
+ running: false
+ repeat: false
+ interval: 800
+ onTriggered: {
+ force.active = false
+ resetter.active = true;
+ mp.take(alertItem, true);
+ centerEmitter.burst(1);
+ }
+ }
+ Attractor{
+ id: force
+ system: sys
+ x: root.width/2
+ y: root.height/2
+ strength: -30000
+ active: false
+ anchors.centerIn: parent
+ width: parent.width/2
+ height: parent.height/2
+ particles:["photos"]
+ }
+ Reset{
+ id: resetter
+ system: sys
+ particles:["photos"]
+ }
+ TrailEmitter{
+ id: centerEmitter
+ speed: PointVector{ x: 32; xVariation: 8;}
+ particlesPerSecond: 0.5
+ particleDuration: 12000 //TODO: A -1 or something which does 'infinite'? (but need disable fade first)
+ maxParticles: 20
+ particle: "photos"
+ system: sys
+ anchors.centerIn: parent
+ emitting: false
+
+ //TODO: Zoom in effect
+ }
+ TrailEmitter{
+ id: spawnFireworks
+ particle: "fireworks"
+ system: sys
+ maxParticles: 400
+ particlesPerSecond: 400
+ particleDuration: 2800
+ x: parent.width/2
+ y: parent.height/2 - 64
+ width: 8
+ height: 8
+ emitting: false
+ particleSize: 32
+ particleEndSize: 8
+ speed: AngleVector{ magnitude: 160; magnitudeVariation: 120; angleVariation: 90; angle: 270 }
+ acceleration: PointVector{ y: 160 }
+ }
+ Item{ x: -1000; y: -1000 //offscreen
+ Repeater{//Load them here, add to system on completed
+ model: theModel
+ delegate: theDelegate
+ }
+ }
+ RssModel{id: theModel; tags:"particle,particles"}
+ Component {
+ id: theDelegate
+ Rectangle {
+ id: container
+ border.width: 2
+ property real myRand: Math.random();//'depth'
+ z: Math.floor(myRand * 100)
+ scale: (myRand + 1.0)/2;
+ //TODO: Darken based on 'depth'
+ width: 132
+ height: 132
+ //ModelParticle.onAttached: console.log("I'm in" + x + "," + y + ":" + opacity);
+ ModelParticle.onDetached: mp.take(container);//respawns
+ function manage()
+ {
+ if(state == "selected"){
+ // console.log("Taking " + index);
+ mp.freeze(container);
+ }else{
+ // console.log("Returning " +index);
+ mp.unfreeze(container);
+ }
+ }
+ Image{
+ id: img
+ anchors.centerIn: parent
+ smooth: true; source: "http://" + Script.getImagePath(content); cache: true
+ fillMode: Image.PreserveAspectFit;
+ width: parent.width-4; height: parent.height-4
+ onStatusChanged: if(img.status == Image.Ready){
+ loading.opacity = 0;
+ mp.take(container);
+ }
+ }
+ Text{
+ anchors.bottom: parent.bottom
+ width: parent.width
+ horizontalAlignment: Text.AlignHCenter
+ elide: Text.ElideRight
+ text: title
+ color: "black"
+ }
+ MouseArea{
+ anchors.fill: parent
+ onClicked: container.state == "selected" ? container.state = "" : container.state = "selected"
+ }
+ states: State{
+ name: "selected"
+ ParentChange{
+ target: container
+ parent: root
+ x: 0
+ y: 0
+ }
+ PropertyChanges{
+ target: container
+ width: root.width
+ height: root.height
+ z: 101
+ opacity: 1
+ rotation: 0
+ }
+ }
+ transitions: Transition{
+ to: "selected"
+ reversible: true
+ SequentialAnimation{
+ ScriptAction{script: container.manage();}
+ ParallelAnimation{
+ ParentAnimation{NumberAnimation{ properties: "x,y" }}//Doesn't work, particles takes control of x,y instantly
+ NumberAnimation{ properties: "width, height, z, rotation" }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/declarative/particles/snow/content/flake-01.png b/examples/declarative/particles/snow/content/flake-01.png
new file mode 100644
index 0000000000..490887a82f
--- /dev/null
+++ b/examples/declarative/particles/snow/content/flake-01.png
Binary files differ
diff --git a/examples/declarative/particles/snow/snow.qml b/examples/declarative/particles/snow/snow.qml
new file mode 100644
index 0000000000..25d2e1468b
--- /dev/null
+++ b/examples/declarative/particles/snow/snow.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ width: 360
+ height: 540
+ ParticleSystem { id: particles }
+ SpriteParticle {
+ system: particles
+ Sprite{
+ name: "snow"
+ source: "content/flake-01.png"
+ frames: 51
+ duration: 40
+ }
+ }
+ Wander {
+ system: particles
+ anchors.fill: parent
+ xVariance: 40;
+ pace: 40;
+ }
+ TrailEmitter {
+ system: particles
+ particlesPerSecond: 20
+ particleDuration: 7000
+ emitting: true
+ speed: PointVector{ y:80; yVariation: 40; }
+ acceleration: PointVector{ y: 4 }
+ particleSize: 20
+ particleSizeVariation: 10
+ width: parent.width
+ height: 100
+ }
+}
diff --git a/examples/declarative/particles/snow/snow2.qml b/examples/declarative/particles/snow/snow2.qml
new file mode 100644
index 0000000000..c016ba2934
--- /dev/null
+++ b/examples/declarative/particles/snow/snow2.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ width: 360
+ height: 540
+ ParticleSystem{ id: particles }
+ SpriteParticle{
+ system: particles
+ Sprite{
+ name: "snow"
+ source: "content/flake-01.png"
+ frames: 51
+ duration: 40
+ }
+ }
+ Drift{
+ system: particles
+ anchors.fill: parent
+ xDrift: 400;
+ }
+ TrailEmitter{
+ system: particles
+ particlesPerSecond: 20
+ particleDuration: 7000
+ emitting: true
+ speed: PointVector{ y:80; yVariation: 40; }
+ acceleration: PointVector{ y: 4 }
+ particleSize: 20
+ particleSizeVariation: 10
+ width: parent.width
+ height: 100
+ }
+}
diff --git a/examples/declarative/particles/snow/snow3.qml b/examples/declarative/particles/snow/snow3.qml
new file mode 100644
index 0000000000..080bc4d1af
--- /dev/null
+++ b/examples/declarative/particles/snow/snow3.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ width: 360
+ height: 540
+ id: root
+ ParticleSystem{ id: particles }
+ SpriteParticle{
+ system: particles
+ sprites: Sprite{
+ name: "snow"
+ source: "content/flake-01.png"
+ frames: 51
+ duration: 40
+ }
+ }
+ Drift{
+ system: particles
+ anchors.fill: parent
+ xDrift: 200
+ }
+ SpeedLimit{
+ system: particles
+ anchors.fill: parent
+ speedLimit: 100
+ }
+ TrailEmitter{
+ system: particles
+ particlesPerSecond: 20
+ particleDuration: 7000
+ emitting: true
+ speed: PointVector{ y:80; yVariation: 40; }
+ acceleration: PointVector{ y: 4 }
+ particleSize: 20
+ particleSizeVariation: 10
+ width: parent.width
+ height: 40
+ }
+}
diff --git a/examples/declarative/particles/spaceexplorer/content/helpers.js b/examples/declarative/particles/spaceexplorer/content/helpers.js
new file mode 100644
index 0000000000..c38c4c0eed
--- /dev/null
+++ b/examples/declarative/particles/spaceexplorer/content/helpers.js
@@ -0,0 +1,8 @@
+function intersects(item, x, y, e){
+ return x+e >= item.x && x-e <= item.x + item.width && y+e >= item.y && y-e <= item.y + item.height;
+}
+
+function direction(x1, y1, x2, y2){
+ return Math.atan2(y2-y1, x2-x1) * (180/Math.PI);
+}
+
diff --git a/examples/declarative/particles/spaceexplorer/content/particle4.png b/examples/declarative/particles/spaceexplorer/content/particle4.png
new file mode 100644
index 0000000000..bc95b703c1
--- /dev/null
+++ b/examples/declarative/particles/spaceexplorer/content/particle4.png
Binary files differ
diff --git a/examples/declarative/particles/spaceexplorer/content/powerupScore.png b/examples/declarative/particles/spaceexplorer/content/powerupScore.png
new file mode 100644
index 0000000000..e8c368aea7
--- /dev/null
+++ b/examples/declarative/particles/spaceexplorer/content/powerupScore.png
Binary files differ
diff --git a/examples/declarative/particles/spaceexplorer/content/powerupScore_gone.png b/examples/declarative/particles/spaceexplorer/content/powerupScore_gone.png
new file mode 100644
index 0000000000..4076327a1a
--- /dev/null
+++ b/examples/declarative/particles/spaceexplorer/content/powerupScore_gone.png
Binary files differ
diff --git a/examples/declarative/particles/spaceexplorer/content/powerupScore_got.png b/examples/declarative/particles/spaceexplorer/content/powerupScore_got.png
new file mode 100644
index 0000000000..4297245d49
--- /dev/null
+++ b/examples/declarative/particles/spaceexplorer/content/powerupScore_got.png
Binary files differ
diff --git a/examples/declarative/particles/spaceexplorer/content/rocket.png b/examples/declarative/particles/spaceexplorer/content/rocket.png
new file mode 100644
index 0000000000..a171610b03
--- /dev/null
+++ b/examples/declarative/particles/spaceexplorer/content/rocket.png
Binary files differ
diff --git a/examples/declarative/particles/spaceexplorer/content/rocket2.png b/examples/declarative/particles/spaceexplorer/content/rocket2.png
new file mode 100644
index 0000000000..7110f8fdc6
--- /dev/null
+++ b/examples/declarative/particles/spaceexplorer/content/rocket2.png
Binary files differ
diff --git a/examples/declarative/particles/spaceexplorer/content/rocketEye.png b/examples/declarative/particles/spaceexplorer/content/rocketEye.png
new file mode 100644
index 0000000000..20005937d2
--- /dev/null
+++ b/examples/declarative/particles/spaceexplorer/content/rocketEye.png
Binary files differ
diff --git a/examples/declarative/particles/spaceexplorer/content/star.png b/examples/declarative/particles/spaceexplorer/content/star.png
new file mode 100644
index 0000000000..0d592cfa87
--- /dev/null
+++ b/examples/declarative/particles/spaceexplorer/content/star.png
Binary files differ
diff --git a/examples/declarative/particles/spaceexplorer/spaceexplorer.qml b/examples/declarative/particles/spaceexplorer/spaceexplorer.qml
new file mode 100644
index 0000000000..091ca0a8b5
--- /dev/null
+++ b/examples/declarative/particles/spaceexplorer/spaceexplorer.qml
@@ -0,0 +1,412 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+import "content/helpers.js" as Helpers
+
+Rectangle{
+ id: root
+ width: 360
+ height: 540
+ color: "black"
+ Image{
+ anchors.centerIn: parent
+ source: "../asteroid/content/finalfrontier.png"
+ }
+ property bool spacePressed: false
+ property int holeSize: 4
+ focus: true
+ Keys.onPressed: {
+ if (event.key == Qt.Key_Space) {
+ spacePressed = true;
+ event.accepted = true;
+ }
+ }
+ Keys.onReleased: {
+ if (event.key == Qt.Key_Space) {
+ spacePressed = false;
+ event.accepted = true;
+ }
+ }
+
+ function fakeMove(){
+ fakeMoving = rocket.x < 80 || rocket.x+rocket.width-root.width > -80 || rocket.y < 80 || rocket.y+rocket.height-root.height > -80;
+ if(fakeMoving)
+ fakeMovementDir = Helpers.direction(root.width/2, root.height/2, rocket.x, rocket.y) + 180;
+ }
+ property bool fakeMoving: false
+ property real fakeMovementDir: 0
+
+ TrailEmitter{
+ particle: "stars2"
+ system: background
+ particlesPerSecond: 60
+ particleDuration: 4000
+ emitting: true
+ particleSize: 10
+ particleSizeVariation: 10
+ anchors.fill: parent
+ }
+ ParticleSystem{ id: background }
+ ColoredParticle{
+ particles: ["stars2"]
+ system: background
+ anchors.fill: parent
+ image: "content/star.png"
+ color: "white"
+ colorVariation: 0.1
+ }
+ Gravity{
+ system: background
+ anchors.fill: parent
+ acceleration: fakeMoving?10:0
+ angle: fakeMovementDir
+ }
+ Text{
+ color: "white"
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ text:"Drag the ship, but don't hit a black hole!"
+ font.pixelSize: 10
+ }
+ Text{
+ color: "white"
+ font.pixelSize: 36
+ anchors.centerIn: parent
+ text: "GAME OVER"
+ opacity: gameOver ? 1 : 0
+ Behavior on opacity{NumberAnimation{}}
+ }
+ Text{
+ color: "white"
+ font.pixelSize: 18
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ anchors.margins: 8
+ text: "Score: " + score
+ }
+ Image{
+ source: "content/star.png"
+ width: 40
+ height: 40
+ anchors.right: parent.right
+ anchors.top: parent.top
+ MouseArea{
+ anchors.fill: parent
+ anchors.margins: -20
+ onClicked: shoot = !shoot
+ }
+ }
+ property int score: 0
+ property bool gameOver: false
+ property bool shoot: true
+ property int maxLives: 3
+ property int lives: maxLives
+ property bool alive: !Helpers.intersects(rocket, gs1.x, gs1.y, holeSize) && !Helpers.intersects(rocket, gs2.x, gs2.y, holeSize) && !Helpers.intersects(rocket, gs3.x, gs3.y, holeSize) && !Helpers.intersects(rocket, gs4.x, gs4.y, holeSize);
+ onAliveChanged: if(!alive){
+ lives -= 1;
+ if(lives == -1){
+ console.log("game over");
+ gameOver = true;
+ }
+ }
+ Row{
+ Repeater{
+ model: maxLives
+ delegate: Image{
+ opacity: index < lives ? 1 : 0
+ Behavior on opacity{NumberAnimation{}}
+ source: "content/rocket.png"
+ }
+ }
+ }
+
+ property real courseDur: 10000
+ property real vorteX: width/4
+ property real vorteY: height/4
+ Behavior on vorteX{NumberAnimation{duration: courseDur}}
+ Behavior on vorteY{NumberAnimation{duration: courseDur}}
+ property real vorteX2: width/4
+ property real vorteY2: 3*height/4
+ Behavior on vorteX2{NumberAnimation{duration: courseDur}}
+ Behavior on vorteY2{NumberAnimation{duration: courseDur}}
+ property real vorteX3: 3*width/4
+ property real vorteY3: height/4
+ Behavior on vorteX3{NumberAnimation{duration: courseDur}}
+ Behavior on vorteY3{NumberAnimation{duration: courseDur}}
+ property real vorteX4: 3*width/4
+ property real vorteY4: 3*height/4
+ Behavior on vorteX4{NumberAnimation{duration: courseDur}}
+ Behavior on vorteY4{NumberAnimation{duration: courseDur}}
+ Timer{
+ id: vorTimer
+ interval: courseDur
+ running: true
+ repeat: true
+ triggeredOnStart: true
+ onTriggered: {
+ vorteX = Math.random() * width * 2 - width * 0.5;
+ vorteY = Math.random() * height * 2 - height * 0.5;
+ vorteX2 = Math.random() * width * 2 - width * 0.5;
+ vorteY2 = Math.random() * height * 2 - height * 0.5;
+ vorteX3 = Math.random() * width * 2 - width * 0.5;
+ vorteY3 = Math.random() * height * 2 - height * 0.5;
+ vorteX4 = Math.random() * width * 2 - width * 0.5;
+ vorteY4 = Math.random() * height * 2 - height * 0.5;
+ }
+ }
+
+
+
+ ParticleSystem{ id: foreground }
+ ColoredParticle{
+ particles: ["stars"]
+ anchors.fill: parent
+ system: foreground
+ image: "content/star.png"
+ color: "white"
+ colorVariation: 0.1
+ }
+ ColoredParticle{
+ particles: ["shot"]
+ anchors.fill: parent
+ system: foreground
+ image: "content/star.png"
+
+ color: "orange"
+ colorVariation: 0.3
+ }
+ ColoredParticle{
+ id: engine
+ particles: ["engine"]
+ anchors.fill: parent
+ system: foreground
+ image: "content/particle4.png"
+
+ color: "orange"
+ SequentialAnimation on color {
+ loops: Animation.Infinite
+ ColorAnimation {
+ from: "red"
+ to: "cyan"
+ duration: 1000
+ }
+ ColorAnimation {
+ from: "cyan"
+ to: "red"
+ duration: 1000
+ }
+ }
+
+ colorVariation: 0.2
+ }
+ SpriteParticle{
+ particles: ["powerups"]
+ anchors.fill: parent
+ system: foreground
+ Sprite{
+ name: "norm"
+ source: "content/powerupScore.png"
+ frames: 35
+ duration: 40
+ to: {"norm":1, "got":0}
+ }
+ Sprite{
+ name: "got"
+ source: "content/powerupScore_got.png"
+ frames: 22
+ duration: 40
+ to: {"null":1}
+ }
+ Sprite{
+ name: "null"
+ source: "content/powerupScore_gone.png"
+ frames: 1
+ duration: 1000
+ }
+ }
+ SpriteGoal{
+ x: rocket.x - 30
+ y: rocket.y - 30
+ width: 60
+ height: 60
+ goalState: "got"
+ jump: true
+ onAffected: if(!gameOver) score += 1000
+ system: foreground
+ }
+ GravitationalSingularity{
+ id: gs1; x: vorteX; y: vorteY; strength: 800000;
+ system: foreground
+ }
+ Kill{
+ x: gs1.x - holeSize;
+ y: gs1.y - holeSize;
+ width: holeSize * 2
+ height: holeSize * 2
+ system: foreground
+ }
+
+ GravitationalSingularity{
+ id: gs2; x: vorteX2; y: vorteY2; strength: 800000;
+ system: foreground
+ }
+ Kill{
+ x: gs2.x - holeSize;
+ y: gs2.y - holeSize;
+ width: holeSize * 2
+ height: holeSize * 2
+ system: foreground
+ }
+
+ GravitationalSingularity{
+ id: gs3; x: vorteX3; y: vorteY3; strength: 800000;
+ system: foreground
+ }
+ Kill{
+ x: gs3.x - holeSize;
+ y: gs3.y - holeSize;
+ width: holeSize * 2
+ height: holeSize * 2
+ system: foreground
+ }
+ GravitationalSingularity{
+ id: gs4; x: vorteX4; y: vorteY4; strength: 800000;
+ system: foreground
+ }
+ Kill{
+ x: gs4.x - holeSize;
+ y: gs4.y - holeSize;
+ width: holeSize * 2
+ height: holeSize * 2
+ system: foreground
+ }
+ TrailEmitter{
+ particle: "powerups"
+ system: foreground
+ particlesPerSecond: 1
+ particleDuration: 6000
+ emitting: !gameOver
+ particleSize: 60
+ particleSizeVariation: 10
+ anchors.fill: parent
+ }
+ TrailEmitter{
+ particle: "stars"
+ system: foreground
+ particlesPerSecond: 40
+ particleDuration: 4000
+ emitting: !gameOver
+ particleSize: 30
+ particleSizeVariation: 10
+ anchors.fill: parent
+ }
+ SpriteImage{
+ id: rocket
+ //Sprites or children for default?
+ Sprite{
+ name: "normal"
+ source: "content/rocket2.png"
+ frames: 1
+ duration: 1000
+ to: {"normal": 0.9, "winking" : 0.1}
+ }
+ Sprite{
+ name: "winking"
+ source: "content/rocketEye.png"
+ frames: 10
+ duration: 40
+ to: {"normal" : 1}
+ }
+ x: root.width/2
+ y: root.height/2
+ property int lx: 0
+ property int ly: 0
+ property int lastX: 0
+ property int lastY: 0
+ width: 45
+ height: 22
+ onXChanged:{ lastX = lx; lx = x; fakeMove()}
+ onYChanged:{ lastY = ly; ly = y; fakeMove()}
+ rotation: Helpers.direction(lastX, lastY, x, y)
+ data:[
+ MouseArea{
+ id: ma
+ anchors.fill: parent;
+ drag.axis: Drag.XandYAxis
+ drag.target: rocket
+ },
+ TrailEmitter{
+ system: foreground
+ particle: "engine"
+ particlesPerSecond: 100
+ particleDuration: 1000
+ emitting: !gameOver
+ particleSize: 10
+ particleEndSize: 4
+ particleSizeVariation: 4
+ speed: PointVector{
+ x: -128 * Math.cos(rocket.rotation * (Math.PI / 180))
+ y: -128 * Math.sin(rocket.rotation * (Math.PI / 180))
+ }
+ anchors.verticalCenter: parent.verticalCenter
+ height: 4
+ width: 4
+
+ },
+ TrailEmitter{
+ system: foreground
+ particle: "shot"
+ particlesPerSecond: 16
+ particleDuration: 1600
+ emitting: !gameOver && shoot
+ particleSize: 40
+ speed: PointVector{
+ x: 256 * Math.cos(rocket.rotation * (Math.PI / 180))
+ y: 256 * Math.sin(rocket.rotation * (Math.PI / 180))
+ }
+ x: parent.width - 4
+ y: parent.height/2
+ }
+ ]
+ }
+}
+
diff --git a/examples/declarative/particles/trails/content/PetsModel.qml b/examples/declarative/particles/trails/content/PetsModel.qml
new file mode 100644
index 0000000000..d7375a73af
--- /dev/null
+++ b/examples/declarative/particles/trails/content/PetsModel.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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 1.0
+
+ListModel {
+ ListElement {
+ name: "Polly"
+ type: "Parrot"
+ age: 12
+ size: "Small"
+ }
+ ListElement {
+ name: "Penny"
+ type: "Turtle"
+ age: 4
+ size: "Small"
+ }
+ ListElement {
+ name: "Warren"
+ type: "Rabbit"
+ age: 2
+ size: "Small"
+ }
+ ListElement {
+ name: "Spot"
+ type: "Dog"
+ age: 9
+ size: "Medium"
+ }
+ ListElement {
+ name: "Schrödinger"
+ type: "Cat"
+ age: 2
+ size: "Medium"
+ }
+ ListElement {
+ name: "Joey"
+ type: "Kangaroo"
+ age: 1
+ size: "Medium"
+ }
+ ListElement {
+ name: "Kimba"
+ type: "Bunny"
+ age: 65
+ size: "Large"
+ }
+ ListElement {
+ name: "Rover"
+ type: "Dog"
+ age: 5
+ size: "Large"
+ }
+ ListElement {
+ name: "Tiny"
+ type: "Elephant"
+ age: 15
+ size: "Large"
+ }
+}
diff --git a/examples/declarative/particles/trails/content/candle.png b/examples/declarative/particles/trails/content/candle.png
new file mode 100644
index 0000000000..8fa3193719
--- /dev/null
+++ b/examples/declarative/particles/trails/content/candle.png
Binary files differ
diff --git a/examples/declarative/particles/trails/content/colortable.png b/examples/declarative/particles/trails/content/colortable.png
new file mode 100644
index 0000000000..a62ceeb4a0
--- /dev/null
+++ b/examples/declarative/particles/trails/content/colortable.png
Binary files differ
diff --git a/examples/declarative/particles/trails/content/particle.png b/examples/declarative/particles/trails/content/particle.png
new file mode 100644
index 0000000000..5c83896d22
--- /dev/null
+++ b/examples/declarative/particles/trails/content/particle.png
Binary files differ
diff --git a/examples/declarative/particles/trails/content/particle2.png b/examples/declarative/particles/trails/content/particle2.png
new file mode 100644
index 0000000000..36349c6c6e
--- /dev/null
+++ b/examples/declarative/particles/trails/content/particle2.png
Binary files differ
diff --git a/examples/declarative/particles/trails/content/particle3.png b/examples/declarative/particles/trails/content/particle3.png
new file mode 100644
index 0000000000..905d8f37b8
--- /dev/null
+++ b/examples/declarative/particles/trails/content/particle3.png
Binary files differ
diff --git a/examples/declarative/particles/trails/content/particleA.png b/examples/declarative/particles/trails/content/particleA.png
new file mode 100644
index 0000000000..c63acdee1f
--- /dev/null
+++ b/examples/declarative/particles/trails/content/particleA.png
Binary files differ
diff --git a/examples/declarative/particles/trails/content/portal_bg.png b/examples/declarative/particles/trails/content/portal_bg.png
new file mode 100644
index 0000000000..3c59eeabb9
--- /dev/null
+++ b/examples/declarative/particles/trails/content/portal_bg.png
Binary files differ
diff --git a/examples/declarative/particles/trails/content/sparkleSize.png b/examples/declarative/particles/trails/content/sparkleSize.png
new file mode 100644
index 0000000000..752056541b
--- /dev/null
+++ b/examples/declarative/particles/trails/content/sparkleSize.png
Binary files differ
diff --git a/examples/declarative/particles/trails/content/star.png b/examples/declarative/particles/trails/content/star.png
new file mode 100644
index 0000000000..0d592cfa87
--- /dev/null
+++ b/examples/declarative/particles/trails/content/star.png
Binary files differ
diff --git a/examples/declarative/particles/trails/dynamicemitters.qml b/examples/declarative/particles/trails/dynamicemitters.qml
new file mode 100644
index 0000000000..8ea0272d94
--- /dev/null
+++ b/examples/declarative/particles/trails/dynamicemitters.qml
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ id: root
+ color: "black"
+ width: 640
+ height: 480
+ ParticleSystem{
+ id: sys
+ }
+ ColoredParticle{
+ system: sys
+ image: "content/particle.png"
+ color: "white"
+ colorVariation: 1.0
+ alpha: 0.1
+ }
+ Component{
+ id: emitterComp
+ TrailEmitter{
+ id: container
+ TrailEmitter{
+ id: emitMore
+ system: sys
+ emitting: true
+ particlesPerSecond: 128
+ particleDuration: 600
+ particleSize: 16
+ particleEndSize: 8
+ speed: AngleVector{angleVariation:360; magnitude: 60}
+ }
+
+ property int life: 2600
+ property real targetX: 0
+ property real targetY: 0
+ function go(){
+ xAnim.start();
+ yAnim.start();
+ container.emitting = true
+ }
+ system: sys
+ emitting: true
+ particlesPerSecond: 64
+ particleDuration: 600
+ particleSize: 24
+ particleEndSize: 8
+ NumberAnimation on x{
+ id: xAnim;
+ to: targetX
+ duration: life
+ running: false
+ }
+ NumberAnimation on y{
+ id: yAnim;
+ to: targetY
+ duration: life
+ running: false
+ }
+ Timer{
+ interval: life
+ running: true
+ onTriggered: container.destroy();
+ }
+ }
+ }
+ MouseArea{
+ anchors.fill: parent
+ onClicked:{
+ for(var i=0; i<16; i++){
+ var obj = emitterComp.createObject(root);
+ obj.x = mouse.x
+ obj.y = mouse.y
+ obj.targetX = Math.random() * 640
+ obj.targetY = Math.random() * 480
+ obj.life = Math.round(Math.random() * 2400) + 200
+ obj.go();
+ }
+ }
+ }
+}
diff --git a/examples/declarative/particles/trails/fireballs.qml b/examples/declarative/particles/trails/fireballs.qml
new file mode 100644
index 0000000000..116a2334dc
--- /dev/null
+++ b/examples/declarative/particles/trails/fireballs.qml
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle {
+ id: root
+ width: 360
+ height: 540
+ color: "black"
+
+ ParticleSystem{
+ id: particles
+ }
+
+ /*
+ ColoredParticle{
+ id: fireball
+ anchors.fill: parent
+ particles: ["E"]
+ system: particles
+ image: "content/particleA.png"
+ colorVariation: 0.2
+ color: "#00ff400f"
+ }
+ */
+ ColoredParticle{
+ id: smoke
+ system: particles
+ anchors.fill: parent
+ particles: ["A", "B"]
+ image: "content/particle.png"
+ colorVariation: 0
+ color: "#00111111"
+ }
+ ColoredParticle{
+ id: flame
+ anchors.fill: parent
+ system: particles
+ particles: ["C", "D"]
+ image: "content/particle.png"
+ colorVariation: 0.1
+ color: "#00ff400f"
+ }
+ TrailEmitter{
+ id: fire
+ system: particles
+ particle: "C"
+
+ y: parent.height
+ width: parent.width
+
+ particlesPerSecond: 350
+ particleDuration: 3500
+
+ acceleration: PointVector{ y: -17; xVariation: 3 }
+ speed: PointVector{xVariation: 3}
+
+ particleSize: 24
+ particleSizeVariation: 8
+ particleEndSize: 4
+ }
+ FollowEmitter{
+ id: fireSmoke
+ particle: "B"
+ system: particles
+ follow: "C"
+ width: root.width
+ height: root.height - 68
+
+ particlesPerParticlePerSecond: 1
+ particleDuration: 2000
+
+ speed: PointVector{y:-17*6; yVariation: -17; xVariation: 3}
+ acceleration: PointVector{xVariation: 3}
+
+ particleSize: 36
+ particleSizeVariation: 8
+ particleEndSize: 16
+ }
+ FollowEmitter{
+ id: fireballFlame
+ anchors.fill: parent
+ system: particles
+ particle: "D"
+ follow: "E"
+
+ particlesPerParticlePerSecond: 120
+ particleDuration: 180
+ emissionWidth: 8
+ emissionHeight: 8
+
+ particleSize: 16
+ particleSizeVariation: 4
+ particleEndSize: 4
+ }
+
+ FollowEmitter{
+ id: fireballSmoke
+ anchors.fill: parent
+ system: particles
+ particle: "A"
+ follow: "E"
+
+ particlesPerParticlePerSecond: 128
+ particleDuration: 2400
+ emissionWidth: 16
+ emissionHeight: 16
+
+ speed: PointVector{yVariation: 16; xVariation: 16}
+ acceleration: PointVector{y: -16}
+
+ particleSize: 24
+ particleSizeVariation: 8
+ particleEndSize: 8
+ }
+ TrailEmitter{
+ id: balls
+ system: particles
+ particle: "E"
+
+ y: parent.height
+ width: parent.width
+
+ particlesPerSecond: 2
+ particleDuration: 7000
+
+ speed: PointVector{y:-17*4*2; xVariation: 6*6}
+ acceleration: PointVector{y: 17*2; xVariation: 6*6}
+
+ particleSize: 12
+ particleSizeVariation: 4
+ }
+
+}
+
diff --git a/examples/declarative/particles/trails/layered.qml b/examples/declarative/particles/trails/layered.qml
new file mode 100644
index 0000000000..38eb8e67dc
--- /dev/null
+++ b/examples/declarative/particles/trails/layered.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ id: root
+ width: 360
+ height: 600
+ color: "darkblue"
+ property bool cloneMode: false
+ MouseArea{
+ anchors.fill: parent
+ onClicked: cloneMode = !cloneMode;
+ }
+ ParticleSystem{
+ id: sys
+ startTime: 4000
+ }
+ TrailEmitter{
+ system: sys
+ y:root.height + 20
+ width: root.width
+ particlesPerSecond: 200
+ particleDuration: 4000
+ speed: PointVector{ y: -120; }
+ }
+ SpriteParticle{
+ system: sys
+ visible: !cloneMode
+ Sprite{
+ source: "content/particle2.png"
+ }
+ }
+ SpriteParticle{
+ system: sys
+ visible: cloneMode
+ z: 0
+ Sprite{
+ source: "content/particle3.png"
+ }
+ }
+ SpriteParticle{
+ system: sys
+ clip: true
+ visible: cloneMode
+ y: 120
+ height: 240
+ width: root.width
+ z: 1
+ Sprite{
+ source: "content/particle.png"
+ }
+ }
+}
diff --git a/examples/declarative/particles/trails/list.qml b/examples/declarative/particles/trails/list.qml
new file mode 100644
index 0000000000..2ab579f126
--- /dev/null
+++ b/examples/declarative/particles/trails/list.qml
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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$
+**
+****************************************************************************/
+
+// This example shows how to create your own highlight delegate for a ListView
+// that uses a SpringAnimation to provide custom movement when the
+// highlight bar is moved between items. + Particles.
+
+import QtQuick 2.0
+import Qt.labs.particles 2.0
+import "content"
+
+Rectangle {
+ width: 200; height: 300
+ color: "black"
+ ParticleSystem{ id: particles }
+ ColoredParticle{
+ anchors.fill: parent
+ system: particles
+ z: 10
+ image: "content/star.png"
+ color: "white"
+ colorVariation: 0.0
+ }
+
+ // Define a delegate component. A component will be
+ // instantiated for each visible item in the list.
+ Component {
+ id: petDelegate
+ Item {
+ id: wrapper
+ width: 200; height: 55
+ Column {
+ Text { text: 'Name: ' + name; color: "white" }
+ Text { text: 'Type: ' + type; color: "white" }
+ Text { text: 'Age: ' + age; color: "white" }
+ }
+ // indent the item if it is the current item
+ states: State {
+ name: "Current"
+ when: wrapper.ListView.isCurrentItem
+ PropertyChanges { target: wrapper; x: 20 }
+ }
+ transitions: Transition {
+ NumberAnimation { properties: "x"; duration: 200 }
+ }
+ }
+ }
+
+ // Define a highlight with customised movement between items.
+ Component {
+ id: highlightBar
+ Rectangle {
+ width: 200; height: 50
+ color: "#333366"
+ y: listView.currentItem.y;
+ //Behavior on y { SpringAnimation { spring: 2; damping: 0.1 } }
+ Behavior on y { NumberAnimation {id: anim} }
+ TrailEmitter{
+ anchors.fill: parent
+ system: particles;
+ emitting: anim.running
+ particlesPerSecond: 600
+ particleDuration: 600
+ particleSize: 16
+ particleEndSize: 8
+ }
+ }
+ }
+
+ ListView {
+ id: listView
+ width: 200; height: parent.height
+
+ model: PetsModel {}
+ delegate: petDelegate
+ focus: true
+
+ // Set the highlight delegate. Note we must also set highlightFollowsCurrentItem
+ // to false so the highlight delegate can control how the highlight is moved.
+ highlight: highlightBar
+ highlightFollowsCurrentItem: false
+ }
+}
diff --git a/examples/declarative/particles/trails/overburst.qml b/examples/declarative/particles/trails/overburst.qml
new file mode 100644
index 0000000000..6ca15972a4
--- /dev/null
+++ b/examples/declarative/particles/trails/overburst.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ color: "black"
+ width: 360
+ height: 540
+ ParticleSystem{ id: sys }
+ ColoredParticle{
+ system: sys
+ id: cp
+ image: "content/particle.png"
+ colorVariation: 0.4
+ color: "#000000FF"
+ }
+ TrailEmitter{
+ //burst on click
+ id: bursty
+ system: sys
+ emitting: ma.pressed
+ x: ma.mouseX
+ y: ma.mouseY
+ particlesPerSecond: 16000
+ particleDuration: 1000
+ maxParticles: 4000
+ acceleration: AngleVector{angleVariation: 360; magnitude: 360; }
+ particleSize: 8
+ particleEndSize: 16
+ particleSizeVariation: 4
+ }
+ MouseArea{
+ anchors.fill: parent
+ id: ma
+ }
+ MouseArea{
+ width: 100
+ height: 100
+ onClicked: sys.overwrite = !sys.overwrite
+ id: ma2
+ Rectangle{
+ anchors.fill: parent
+ color: "lightsteelblue"
+ }
+ }
+}
diff --git a/examples/declarative/particles/trails/portal.qml b/examples/declarative/particles/trails/portal.qml
new file mode 100644
index 0000000000..dba2e59513
--- /dev/null
+++ b/examples/declarative/particles/trails/portal.qml
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ id: root
+ width: 360
+ height: 540
+ color: "black"
+ Image{
+ anchors.fill: parent
+ source: "content/portal_bg.png"
+ }
+ ParticleSystem{
+ id: particles
+ startTime: 2000
+ }
+ ColoredParticle{
+ particles: ["center","edge"]
+ anchors.fill: parent
+ system: particles
+ image: "content/particle.png"
+ colorVariation: 0.1
+ color: "#009999FF"
+ }
+ TrailEmitter{
+ anchors.fill: parent
+ particle: "center"
+ system: particles
+ particlesPerSecond: 200
+ particleDuration: 2000
+ emitting: true
+ particleSize: 20
+ particleSizeVariation: 2
+ particleEndSize: 0
+ shape: Ellipse{fill: false}
+ speed: DirectedVector{
+ targetX: root.width/2
+ targetY: root.height/2
+ proportionalMagnitude: true
+ magnitude: 0.5
+ }
+ }
+ TrailEmitter{
+ anchors.fill: parent
+ particle: "edge"
+ system: particles
+ particlesPerSecond: 4000
+ particleDuration: 2000
+ emitting: true
+ particleSize: 20
+ particleSizeVariation: 2
+ particleEndSize: 0
+ shape: Ellipse{fill: false}
+ speed: DirectedVector{
+ targetX: root.width/2
+ targetY: root.height/2
+ proportionalMagnitude: true
+ magnitude: 0.1
+ magnitudeVariation: 0.1
+ }
+ acceleration: DirectedVector{
+ targetX: root.width/2
+ targetY: root.height/2
+ targetVariation: 200
+ proportionalMagnitude: true
+ magnitude: 0.1
+ magnitudeVariation: 0.1
+ }
+ }
+}
diff --git a/examples/declarative/particles/trails/rainbow.qml b/examples/declarative/particles/trails/rainbow.qml
new file mode 100644
index 0000000000..6c64929668
--- /dev/null
+++ b/examples/declarative/particles/trails/rainbow.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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 Qt.labs.particles 2.0
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width: 360
+ height: 540
+ color: "black"
+
+ ParticleSystem{ id: particles }
+ ColoredParticle{
+ system: particles
+ colorVariation: 0.5
+ alpha: 0
+
+ image: "content/particle.png"
+ colorTable: "content/colortable.png"
+ sizeTable: "content/colortable.png"
+ }
+ TrailEmitter{
+ system: particles
+ particlesPerSecond: 500
+ particleDuration: 2000
+
+ y: root.height / 2 + Math.sin(t * 2) * root.height * 0.3
+ x: root.width / 2 + Math.cos(t) * root.width * 0.3
+ property real t;
+
+ NumberAnimation on t {
+ from: 0; to: Math.PI * 2; duration: 10000; loops: Animation.Infinite
+ }
+
+ speedFromMovement: 20
+
+ speed: PointVector{ xVariation: 5; yVariation: 5;}
+ acceleration: PointVector{ xVariation: 5; yVariation: 5;}
+
+ particleSize: 16
+ //particleEndSize: 8
+ //particleSizeVariation: 8
+ }
+}
diff --git a/examples/declarative/particles/trails/shimmer.qml b/examples/declarative/particles/trails/shimmer.qml
new file mode 100644
index 0000000000..06f599d97a
--- /dev/null
+++ b/examples/declarative/particles/trails/shimmer.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ width: 360
+ height: 540
+ color: "black"
+ MouseArea{
+ anchors.fill: parent
+ onClicked: particles.running = !particles.running
+ }
+ ParticleSystem{
+ id: particles
+ running: false
+ }
+ ColoredParticle{
+ anchors.fill: parent
+ system: particles
+ image: "content/star.png"
+ sizeTable: "content/sparkleSize.png"
+ alpha: 0
+ colorVariation: 0.6
+ }
+ TrailEmitter{
+ anchors.fill: parent
+ system: particles
+ particlesPerSecond: 2000
+ particleDuration: 2000
+ emitting: true
+ particleSize: 30
+ particleSizeVariation: 10
+ }
+}
diff --git a/examples/declarative/particles/trails/swarm.qml b/examples/declarative/particles/trails/swarm.qml
new file mode 100644
index 0000000000..083f9e816d
--- /dev/null
+++ b/examples/declarative/particles/trails/swarm.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0 as QLP
+
+Rectangle{
+ width: 200
+ height: 200
+ color: "black"
+ QLP.ParticleSystem{ id: ps }
+ QLP.ColoredParticle{
+ system: ps
+ particles: ["star1","star2"]
+ anchors.fill: parent
+ clip: true
+ image: "content/star.png"
+ }
+ QLP.Swarm{
+ system: ps
+ leaders: ["star2"];
+ anchors.fill: parent
+ strength: 128
+ }
+ QLP.TrailEmitter{
+ anchors.fill: parent
+ system: ps
+ particle: "star1"
+ particlesPerSecond: 100
+ particleDuration: 2000
+ }
+ QLP.TrailEmitter{
+ anchors.fill: parent
+ system: ps
+ particle: "star2"
+ particlesPerSecond: 0.4
+ particleDuration: 10000
+ particleSize: 64
+ particleEndSize: 32
+ }
+}
diff --git a/examples/declarative/particles/trails/trails.qml b/examples/declarative/particles/trails/trails.qml
new file mode 100644
index 0000000000..58d369c8d5
--- /dev/null
+++ b/examples/declarative/particles/trails/trails.qml
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ color: "black"
+ width: 360
+ height: 540
+ ParticleSystem{ id: sys }
+ ColoredParticle{
+ system: sys
+ id: cp
+ image: "content/particle.png"
+ color: "#00FFFFFF"
+ colorVariation: 0.4
+ }
+ TrailEmitter{
+ //burst on click
+ id: bursty
+ system: sys
+ emitting: false
+ particlesPerSecond: 2000
+ particleDuration: 500
+ acceleration: AngleVector{ angle: 90; angleVariation: 360; magnitude: 640; }
+ particleSize: 8
+ particleEndSize: 16
+ particleSizeVariation: 4
+ }
+ TrailEmitter{
+ system: sys
+ speedFromMovement: 4.0
+ emitting: ma.pressed
+ x: ma.mouseX
+ y: ma.mouseY
+ particlesPerSecond: 400
+ particleDuration: 2000
+ acceleration: AngleVector{ angle: 90; angleVariation: 22; magnitude: 32; }
+ particleSize: 8
+ particleEndSize: 16
+ particleSizeVariation: 8
+ }
+ MouseArea{
+ id: ma
+ anchors.fill: parent
+ onPressed: {bursty.x = mouse.x; bursty.y = mouse.y; bursty.pulse(0.1);}//uses both for comparison
+ onReleased: {bursty.x = mouse.x; bursty.y = mouse.y; bursty.burst(200);}
+ }
+}
diff --git a/examples/declarative/particles/trails/turbulence.qml b/examples/declarative/particles/trails/turbulence.qml
new file mode 100644
index 0000000000..7da50464c2
--- /dev/null
+++ b/examples/declarative/particles/trails/turbulence.qml
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle{
+ width: 360
+ height: 540
+ color: "#222222"
+ id: root
+ Image{
+ source: "content/candle.png"
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottomMargin: -8
+ anchors.horizontalCenterOffset: 2
+ }
+ ParticleSystem{
+ id: ps
+ }
+ Turbulence{
+ system: ps
+ height: (parent.height / 2)
+ width: parent.width / 2
+ x: parent. width / 4
+ anchors.fill: parent
+ strength: 16
+ frequency: 64
+ gridSize: 16
+ }
+ ColoredParticle{
+ particles: ["smoke"]
+ system: ps
+ image: "content/particle.png"
+ color: "#11111111"
+ colorVariation: 0
+ }
+ ColoredParticle{
+ particles: ["flame"]
+ system: ps
+ image: "content/particle.png"
+ color: "#11ff400f"
+ colorVariation: 0.1
+ }
+ TrailEmitter{
+ anchors.centerIn: parent
+ system: ps
+ particle: "flame"
+
+ particlesPerSecond: 120
+ particleDuration: 1200
+ particleSize: 20
+ particleEndSize: 10
+ particleSizeVariation: 10
+ acceleration: PointVector{ y: -40 }
+ speed: AngleVector{ angle: 270; magnitude: 20; angleVariation: 22; magnitudeVariation: 5 }
+ }
+ FollowEmitter{
+ id: smoke1
+ width: root.width
+ height: 232
+ system: ps
+ particle: "smoke"
+ follow: "flame"
+
+ particlesPerParticlePerSecond: 4
+ particleDuration: 2400
+ particleDurationVariation: 400
+ particleSize: 16
+ particleEndSize: 8
+ particleSizeVariation: 8
+ acceleration: PointVector{ y: -40 }
+ speed: AngleVector{ angle: 270; magnitude: 40; angleVariation: 22; magnitudeVariation: 5 }
+ }
+ FollowEmitter{
+ id: smoke2
+ width: root.width
+ height: 232
+ system: ps
+ particle: "smoke"
+ follow: "flame"
+
+ particlesPerParticlePerSecond: 1
+ particleDuration: 2400
+ particleSize: 36
+ particleEndSize: 24
+ particleSizeVariation: 8
+ acceleration: PointVector{ y: -40 }
+ speed: AngleVector{ angle: 270; magnitude: 40; angleVariation: 22; magnitudeVariation: 5 }
+ }
+}
diff --git a/examples/declarative/particles/trails/velocityfrommotion.qml b/examples/declarative/particles/trails/velocityfrommotion.qml
new file mode 100644
index 0000000000..3692410853
--- /dev/null
+++ b/examples/declarative/particles/trails/velocityfrommotion.qml
@@ -0,0 +1,327 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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
+import Qt.labs.particles 2.0
+
+Rectangle {
+
+ id: root
+
+ height: 540
+ width: 360
+
+ gradient: Gradient {
+ GradientStop { position: 0; color: "#000020" }
+ GradientStop { position: 1; color: "#000000" }
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: root
+
+/*
+ onPressed: stopAndStart()
+ onReleased: stopAndStart()
+ function stopAndStart() {
+ trailsNormal.emitting = false;
+ trailsNormal.emitting = true;
+ trailsStars.emitting = false;
+ trailsStars.emitting = true;
+ trailsNormal2.emitting = false;
+ trailsNormal2.emitting = true;
+ trailsStars2.emitting = false;
+ trailsStars2.emitting = true;
+ print("stop and start")
+ }
+*/
+ }
+
+ ParticleSystem{ id: sys1 }
+ ColoredParticle{
+ system: sys1
+ image: "content/particle.png"
+ color: "cyan"
+ alpha: 0
+ SequentialAnimation on color {
+ loops: Animation.Infinite
+ ColorAnimation {
+ from: "cyan"
+ to: "magenta"
+ duration: 1000
+ }
+ ColorAnimation {
+ from: "magenta"
+ to: "blue"
+ duration: 2000
+ }
+ ColorAnimation {
+ from: "blue"
+ to: "violet"
+ duration: 2000
+ }
+ ColorAnimation {
+ from: "violet"
+ to: "cyan"
+ duration: 2000
+ }
+ }
+ colorVariation: 0.3
+ }
+ TrailEmitter{
+ id: trailsNormal
+ system: sys1
+
+ particlesPerSecond: 500
+ particleDuration: 2000
+
+
+ y: mouseArea.pressed ? mouseArea.mouseY : circle.cy
+ x: mouseArea.pressed ? mouseArea.mouseX : circle.cx
+
+ speed: PointVector{xVariation: 4; yVariation: 4;}
+ acceleration: PointVector{xVariation: 10; yVariation: 10;}
+ speedFromMovement: 8
+
+ particleSize: 8
+ particleSizeVariation: 4
+ }
+ ParticleSystem { id: sys2 }
+ ColoredParticle{
+ color: "cyan"
+ system: sys2
+ alpha: 0
+ SequentialAnimation on color {
+ loops: Animation.Infinite
+ ColorAnimation {
+ from: "magenta"
+ to: "cyan"
+ duration: 1000
+ }
+ ColorAnimation {
+ from: "cyan"
+ to: "magenta"
+ duration: 2000
+ }
+ }
+ colorVariation: 0.5
+ image: "content/star.png"
+ }
+ TrailEmitter{
+ id: trailsStars
+ system: sys2
+
+ particlesPerSecond: 100
+ particleDuration: 2200
+
+
+ y: mouseArea.pressed ? mouseArea.mouseY : circle.cy
+ x: mouseArea.pressed ? mouseArea.mouseX : circle.cx
+
+ speed: PointVector{xVariation: 4; yVariation: 4;}
+ acceleration: PointVector{xVariation: 10; yVariation: 10;}
+ speedFromMovement: 8
+
+ particleSize: 22
+ particleSizeVariation: 4
+ }
+ ParticleSystem { id: sys3; }
+ ColoredParticle{
+ image: "content/particle.png"
+ system: sys3
+ color: "orange"
+ alpha: 0
+ SequentialAnimation on color {
+ loops: Animation.Infinite
+ ColorAnimation {
+ from: "red"
+ to: "green"
+ duration: 2000
+ }
+ ColorAnimation {
+ from: "green"
+ to: "red"
+ duration: 2000
+ }
+ }
+
+ colorVariation: 0.2
+
+ }
+ TrailEmitter{
+ id: trailsNormal2
+ system: sys3
+
+ particlesPerSecond: 300
+ particleDuration: 2000
+
+ y: mouseArea.pressed ? mouseArea.mouseY : circle2.cy
+ x: mouseArea.pressed ? mouseArea.mouseX : circle2.cx
+
+ speedFromMovement: 16
+
+ speed: PointVector{xVariation: 4; yVariation: 4;}
+ acceleration: PointVector{xVariation: 10; yVariation: 10;}
+
+ particleSize: 12
+ particleSizeVariation: 4
+ }
+ ParticleSystem { id: sys4; }
+ ColoredParticle{
+ system: sys4
+ image: "content/star.png"
+ color: "green"
+ alpha: 0
+ SequentialAnimation on color {
+ loops: Animation.Infinite
+ ColorAnimation {
+ from: "green"
+ to: "red"
+ duration: 2000
+ }
+ ColorAnimation {
+ from: "red"
+ to: "green"
+ duration: 2000
+ }
+ }
+
+ colorVariation: 0.5
+ }
+ TrailEmitter{
+ id: trailsStars2
+ system: sys4
+
+ particlesPerSecond: 50
+ particleDuration: 2200
+
+
+ y: mouseArea.pressed ? mouseArea.mouseY : circle2.cy
+ x: mouseArea.pressed ? mouseArea.mouseX : circle2.cx
+
+ speedFromMovement: 16
+ speed: PointVector{xVariation: 2; yVariation: 2;}
+ acceleration: PointVector{xVariation: 10; yVariation: 10;}
+
+ particleSize: 22
+ particleSizeVariation: 4
+ }
+
+
+
+ color: "white"
+
+ Item {
+ id: circle
+ //anchors.fill: parent
+ property real radius: 0
+ property real dx: root.width / 2
+ property real dy: root.height / 2
+ property real cx: radius * Math.sin(percent*6.283185307179) + dx
+ property real cy: radius * Math.cos(percent*6.283185307179) + dy
+ property real percent: 0
+
+ SequentialAnimation on percent {
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ duration: 1000
+ from: 1
+ to: 0
+ loops: 8
+ }
+ NumberAnimation {
+ duration: 1000
+ from: 0
+ to: 1
+ loops: 8
+ }
+
+ }
+
+ SequentialAnimation on radius {
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ duration: 4000
+ from: 0
+ to: 100
+ }
+ NumberAnimation {
+ duration: 4000
+ from: 100
+ to: 0
+ }
+ }
+ }
+
+ Item {
+ id: circle3
+ property real radius: 100
+ property real dx: root.width / 2
+ property real dy: root.height / 2
+ property real cx: radius * Math.sin(percent*6.283185307179) + dx
+ property real cy: radius * Math.cos(percent*6.283185307179) + dy
+ property real percent: 0
+
+ SequentialAnimation on percent {
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation { from: 0.0; to: 1 ; duration: 10000; }
+ }
+ }
+
+ Item {
+ id: circle2
+ property real radius: 30
+ property real dx: circle3.cx
+ property real dy: circle3.cy
+ property real cx: radius * Math.sin(percent*6.283185307179) + dx
+ property real cy: radius * Math.cos(percent*6.283185307179) + dy
+ property real percent: 0
+
+ SequentialAnimation on percent {
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation { from: 0.0; to: 1 ; duration: 1000; }
+ }
+ }
+
+}
diff --git a/src/declarative/debugger/qdeclarativedebug.cpp b/src/declarative/debugger/qdeclarativedebug.cpp
index 62eb8fea3e..049e05ea06 100644
--- a/src/declarative/debugger/qdeclarativedebug.cpp
+++ b/src/declarative/debugger/qdeclarativedebug.cpp
@@ -84,6 +84,7 @@ public:
static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugRootContextQuery *);
static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugObjectQuery *);
static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugExpressionQuery *);
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugWatch *);
QHash<int, QDeclarativeDebugEnginesQuery *> enginesQuery;
QHash<int, QDeclarativeDebugRootContextQuery *> rootContextQuery;
@@ -120,6 +121,41 @@ QDeclarativeEngineDebugPrivate::~QDeclarativeEngineDebugPrivate()
{
if (client)
client->priv = 0;
+ delete client;
+
+ QHash<int, QDeclarativeDebugEnginesQuery*>::iterator enginesIter = enginesQuery.begin();
+ for (; enginesIter != enginesQuery.end(); ++enginesIter) {
+ enginesIter.value()->m_client = 0;
+ if (enginesIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ enginesIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugRootContextQuery*>::iterator rootContextIter = rootContextQuery.begin();
+ for (; rootContextIter != rootContextQuery.end(); ++rootContextIter) {
+ rootContextIter.value()->m_client = 0;
+ if (rootContextIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ rootContextIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugObjectQuery*>::iterator objectIter = objectQuery.begin();
+ for (; objectIter != objectQuery.end(); ++objectIter) {
+ objectIter.value()->m_client = 0;
+ if (objectIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ objectIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugExpressionQuery*>::iterator exprIter = expressionQuery.begin();
+ for (; exprIter != expressionQuery.end(); ++exprIter) {
+ exprIter.value()->m_client = 0;
+ if (exprIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ exprIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugWatch*>::iterator watchIter = watched.begin();
+ for (; watchIter != watched.end(); ++watchIter) {
+ watchIter.value()->m_client = 0;
+ watchIter.value()->setState(QDeclarativeDebugWatch::Dead);
+ }
}
int QDeclarativeEngineDebugPrivate::getId()
@@ -160,6 +196,14 @@ void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclara
}
}
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclarativeDebugWatch *w)
+{
+ if (c && w) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->watched.remove(w->m_queryId);
+ }
+}
+
void QDeclarativeEngineDebugPrivate::decode(QDataStream &ds, QDeclarativeDebugObjectReference &o,
bool simple)
{
@@ -647,6 +691,8 @@ QDeclarativeDebugWatch::QDeclarativeDebugWatch(QObject *parent)
QDeclarativeDebugWatch::~QDeclarativeDebugWatch()
{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
}
int QDeclarativeDebugWatch::queryId() const
diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp
index 6f46354a49..208f77ea95 100644
--- a/src/declarative/debugger/qdeclarativedebugserver.cpp
+++ b/src/declarative/debugger/qdeclarativedebugserver.cpp
@@ -90,7 +90,11 @@ public:
QHash<QString, QDeclarativeDebugService *> plugins;
QStringList clientPlugins;
bool gotHello;
+ QString waitingForMsgFromService;
+private:
+ // private slot
+ void _q_deliverMessage(const QString &serviceName, const QByteArray &message);
static QDeclarativeDebugServerConnection *loadConnectionPlugin(const QString &pluginName);
};
@@ -235,7 +239,6 @@ void QDeclarativeDebugServer::receiveMessage(const QByteArray &message)
QDataStream in(message);
if (!d->gotHello) {
-
QString name;
int op;
in >> name >> op;
@@ -304,17 +307,33 @@ void QDeclarativeDebugServer::receiveMessage(const QByteArray &message)
QByteArray message;
in >> message;
- QHash<QString, QDeclarativeDebugService *>::Iterator iter =
- d->plugins.find(name);
- if (iter == d->plugins.end()) {
- qWarning() << "QDeclarativeDebugServer: Message received for missing plugin" << name;
+ if (d->waitingForMsgFromService == name) {
+ // deliver directly so that it is delivered before waitForMessage is returning.
+ d->_q_deliverMessage(name, message);
+ d->waitingForMsgFromService.clear();
} else {
- (*iter)->messageReceived(message);
+ // deliver message in next event loop run.
+ // Fixes the case that the service does start it's own event loop ...,
+ // but the networking code doesn't deliver any new messages because readyRead
+ // hasn't returned.
+ QMetaObject::invokeMethod(this, "_q_deliverMessage", Qt::QueuedConnection,
+ Q_ARG(QString, name),
+ Q_ARG(QByteArray, message));
}
}
}
}
+void QDeclarativeDebugServerPrivate::_q_deliverMessage(const QString &serviceName, const QByteArray &message)
+{
+ QHash<QString, QDeclarativeDebugService *>::Iterator iter = plugins.find(serviceName);
+ if (iter == plugins.end()) {
+ qWarning() << "QDeclarativeDebugServer: Message received for missing plugin" << serviceName;
+ } else {
+ (*iter)->messageReceived(message);
+ }
+}
+
QList<QDeclarativeDebugService*> QDeclarativeDebugServer::services() const
{
const Q_D(QDeclarativeDebugServer);
@@ -372,4 +391,23 @@ void QDeclarativeDebugServer::sendMessage(QDeclarativeDebugService *service,
d->connection->send(msg);
}
+bool QDeclarativeDebugServer::waitForMessage(QDeclarativeDebugService *service)
+{
+ Q_D(QDeclarativeDebugServer);
+
+ if (!service
+ || !d->plugins.contains(service->name())
+ || !d->waitingForMsgFromService.isEmpty())
+ return false;
+
+ d->waitingForMsgFromService = service->name();
+
+ do {
+ d->connection->waitForMessage();
+ } while (!d->waitingForMsgFromService.isEmpty());
+ return true;
+}
+
QT_END_NAMESPACE
+
+#include "moc_qdeclarativedebugserver_p.cpp"
diff --git a/src/declarative/debugger/qdeclarativedebugserver_p.h b/src/declarative/debugger/qdeclarativedebugserver_p.h
index 68ea4d8531..72c664c768 100644
--- a/src/declarative/debugger/qdeclarativedebugserver_p.h
+++ b/src/declarative/debugger/qdeclarativedebugserver_p.h
@@ -75,10 +75,13 @@ public:
void sendMessage(QDeclarativeDebugService *service, const QByteArray &message);
void receiveMessage(const QByteArray &message);
+ bool waitForMessage(QDeclarativeDebugService *service);
+
private:
friend class QDeclarativeDebugService;
friend class QDeclarativeDebugServicePrivate;
QDeclarativeDebugServer();
+ Q_PRIVATE_SLOT(d_func(), void _q_deliverMessage(QString, QByteArray))
};
QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebugserverconnection_p.h b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h
index 0c2bdb4ef2..ca267e0662 100644
--- a/src/declarative/debugger/qdeclarativedebugserverconnection_p.h
+++ b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h
@@ -62,6 +62,7 @@ public:
virtual bool isConnected() const = 0;
virtual void send(const QByteArray &message) = 0;
virtual void disconnect() = 0;
+ virtual bool waitForMessage() = 0;
};
Q_DECLARE_INTERFACE(QDeclarativeDebugServerConnection, "com.trolltech.Qt.QDeclarativeDebugServerConnection/1.0")
diff --git a/src/declarative/debugger/qdeclarativedebugservice.cpp b/src/declarative/debugger/qdeclarativedebugservice.cpp
index 1b39f1c269..c7e6615d52 100644
--- a/src/declarative/debugger/qdeclarativedebugservice.cpp
+++ b/src/declarative/debugger/qdeclarativedebugservice.cpp
@@ -209,6 +209,16 @@ void QDeclarativeDebugService::sendMessage(const QByteArray &message)
d->server->sendMessage(this, message);
}
+bool QDeclarativeDebugService::waitForMessage()
+{
+ Q_D(QDeclarativeDebugService);
+
+ if (status() != Enabled)
+ return false;
+
+ return d->server->waitForMessage(this);
+}
+
void QDeclarativeDebugService::statusChanged(Status)
{
}
diff --git a/src/declarative/debugger/qdeclarativedebugservice_p.h b/src/declarative/debugger/qdeclarativedebugservice_p.h
index 5e30350abf..f3d191995f 100644
--- a/src/declarative/debugger/qdeclarativedebugservice_p.h
+++ b/src/declarative/debugger/qdeclarativedebugservice_p.h
@@ -69,6 +69,7 @@ public:
Status status() const;
void sendMessage(const QByteArray &);
+ bool waitForMessage();
static int idForObject(QObject *);
static QObject *objectForId(int);
@@ -84,6 +85,7 @@ protected:
private:
friend class QDeclarativeDebugServer;
+ friend class QDeclarativeDebugServerPrivate;
};
QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebugtrace.cpp b/src/declarative/debugger/qdeclarativedebugtrace.cpp
index 6f28736f52..edbbe78761 100644
--- a/src/declarative/debugger/qdeclarativedebugtrace.cpp
+++ b/src/declarative/debugger/qdeclarativedebugtrace.cpp
@@ -65,9 +65,14 @@ QByteArray QDeclarativeDebugData::toByteArray() const
QDeclarativeDebugTrace::QDeclarativeDebugTrace()
: QDeclarativeDebugService(QLatin1String("CanvasFrameRate")),
- m_enabled(false), m_deferredSend(true)
+ m_enabled(false), m_deferredSend(true), m_messageReceived(false)
{
m_timer.start();
+ if (status() == Enabled) {
+ // wait for first message indicating whether to trace or not
+ while (!m_messageReceived)
+ waitForMessage();
+ }
}
void QDeclarativeDebugTrace::addEvent(EventType t)
@@ -213,6 +218,8 @@ void QDeclarativeDebugTrace::messageReceived(const QByteArray &message)
stream >> m_enabled;
+ m_messageReceived = true;
+
if (!m_enabled)
sendMessages();
}
diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h
index ae0653ee71..c74cbe0120 100644
--- a/src/declarative/debugger/qdeclarativedebugtrace_p.h
+++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h
@@ -120,6 +120,7 @@ private:
QPerformanceTimer m_timer;
bool m_enabled;
bool m_deferredSend;
+ bool m_messageReceived;
QList<QDeclarativeDebugData> m_data;
};
diff --git a/src/declarative/debugger/qpacketprotocol.cpp b/src/declarative/debugger/qpacketprotocol.cpp
index 15a14cf9f4..c1034a79e4 100644
--- a/src/declarative/debugger/qpacketprotocol.cpp
+++ b/src/declarative/debugger/qpacketprotocol.cpp
@@ -42,6 +42,7 @@
#include "private/qpacketprotocol_p.h"
#include <QBuffer>
+#include <QElapsedTimer>
QT_BEGIN_NAMESPACE
@@ -114,7 +115,7 @@ Q_OBJECT
public:
QPacketProtocolPrivate(QPacketProtocol * parent, QIODevice * _dev)
: QObject(parent), inProgressSize(-1), maxPacketSize(MAX_PACKET_SIZE),
- dev(_dev)
+ waitingForPacket(false), dev(_dev)
{
Q_ASSERT(4 == sizeof(qint32));
@@ -125,7 +126,7 @@ public:
QObject::connect(this, SIGNAL(invalidPacket()),
parent, SIGNAL(invalidPacket()));
QObject::connect(dev, SIGNAL(readyRead()),
- this, SLOT(readyToRead()), Qt::QueuedConnection);
+ this, SLOT(readyToRead()));
QObject::connect(dev, SIGNAL(aboutToClose()),
this, SLOT(aboutToClose()));
QObject::connect(dev, SIGNAL(bytesWritten(qint64)),
@@ -200,6 +201,7 @@ public Q_SLOTS:
inProgress.clear();
emit readyRead();
+ waitingForPacket = false;
// Need to get trailing data
readyToRead();
@@ -213,6 +215,7 @@ public:
QByteArray inProgress;
qint32 inProgressSize;
qint32 maxPacketSize;
+ bool waitingForPacket;
QIODevice * dev;
};
@@ -324,6 +327,48 @@ QPacket QPacketProtocol::read()
return rv;
}
+/*
+ Returns the difference between msecs and elapsed. If msecs is -1,
+ however, -1 is returned.
+*/
+static int qt_timeout_value(int msecs, int elapsed)
+{
+ if (msecs == -1)
+ return -1;
+
+ int timeout = msecs - elapsed;
+ return timeout < 0 ? 0 : timeout;
+}
+
+/*!
+ This function locks until a new packet is available for reading and the
+ \l{QIODevice::}{readyRead()} signal has been emitted. The function
+ will timeout after \a msecs milliseconds; the default timeout is
+ 30000 milliseconds.
+
+ The function returns true if the readyRead() signal is emitted and
+ there is new data available for reading; otherwise it returns false
+ (if an error occurred or the operation timed out).
+ */
+
+bool QPacketProtocol::waitForReadyRead(int msecs)
+{
+ if (!d->packets.isEmpty())
+ return true;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ d->waitingForPacket = true;
+ do {
+ if (!d->dev->waitForReadyRead(msecs))
+ return false;
+ if (!d->waitingForPacket)
+ return true;
+ msecs = qt_timeout_value(msecs, stopWatch.elapsed());
+ } while (true);
+}
+
/*!
Return the QIODevice passed to the QPacketProtocol constructor.
*/
diff --git a/src/declarative/debugger/qpacketprotocol_p.h b/src/declarative/debugger/qpacketprotocol_p.h
index accb8efa67..22bc3c250b 100644
--- a/src/declarative/debugger/qpacketprotocol_p.h
+++ b/src/declarative/debugger/qpacketprotocol_p.h
@@ -75,6 +75,8 @@ public:
qint64 packetsAvailable() const;
QPacket read();
+ bool waitForReadyRead(int msecs = 3000);
+
void clear();
QIODevice * device();
diff --git a/src/declarative/declarative.pro b/src/declarative/declarative.pro
index b74b18c090..8c59ee6f74 100644
--- a/src/declarative/declarative.pro
+++ b/src/declarative/declarative.pro
@@ -23,6 +23,8 @@ include(util/util.pri)
include(graphicsitems/graphicsitems.pri)
include(qml/qml.pri)
include(debugger/debugger.pri)
+include(scenegraph/scenegraph.pri)
+include(items/items.pri)
symbian: {
TARGET.UID3=0x2001E623
diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp
index 6602dda28b..d3132deced 100644
--- a/src/declarative/graphicsitems/qdeclarativeitem.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp
@@ -449,6 +449,12 @@ void QDeclarativeItemKeyFilter::componentComplete()
a chain of items with the same KeyNavigation handler. If multiple items in a row are not enabled
or visible, they will also be skipped.
+ KeyNavigation will implicitly set the other direction to return focus to this item. So if you set
+ \l left to another item, \l right will be set on that item's KeyNavigation to set focus back to this
+ item. However, if that item's KeyNavigation has had right explicitly set then no change will occur.
+ This means that the above example could have been written, with the same behaviour, without specifing
+ KeyNavigation.right or KeyNavigation.down for any of the items.
+
\sa {Keys}{Keys attached property}
*/
@@ -498,6 +504,13 @@ void QDeclarativeKeyNavigationAttached::setLeft(QDeclarativeItem *i)
if (d->left == i)
return;
d->left = i;
+ d->leftSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->rightSet){
+ other->d_func()->right = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->rightChanged();
+ }
emit leftChanged();
}
@@ -513,6 +526,13 @@ void QDeclarativeKeyNavigationAttached::setRight(QDeclarativeItem *i)
if (d->right == i)
return;
d->right = i;
+ d->rightSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->leftSet){
+ other->d_func()->left = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->leftChanged();
+ }
emit rightChanged();
}
@@ -528,6 +548,13 @@ void QDeclarativeKeyNavigationAttached::setUp(QDeclarativeItem *i)
if (d->up == i)
return;
d->up = i;
+ d->upSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->downSet){
+ other->d_func()->down = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->downChanged();
+ }
emit upChanged();
}
@@ -543,6 +570,13 @@ void QDeclarativeKeyNavigationAttached::setDown(QDeclarativeItem *i)
if (d->down == i)
return;
d->down = i;
+ d->downSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->upSet){
+ other->d_func()->up = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->upChanged();
+ }
emit downChanged();
}
@@ -558,6 +592,13 @@ void QDeclarativeKeyNavigationAttached::setTab(QDeclarativeItem *i)
if (d->tab == i)
return;
d->tab = i;
+ d->tabSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->backtabSet){
+ other->d_func()->backtab = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->backtabChanged();
+ }
emit tabChanged();
}
@@ -573,6 +614,13 @@ void QDeclarativeKeyNavigationAttached::setBacktab(QDeclarativeItem *i)
if (d->backtab == i)
return;
d->backtab = i;
+ d->backtabSet = true;
+ QDeclarativeKeyNavigationAttached* other =
+ qobject_cast<QDeclarativeKeyNavigationAttached*>(qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(i));
+ if(other && !other->d_func()->tabSet){
+ other->d_func()->tab = qobject_cast<QDeclarativeItem*>(parent());
+ emit other->tabChanged();
+ }
emit backtabChanged();
}
diff --git a/src/declarative/graphicsitems/qdeclarativeitem_p.h b/src/declarative/graphicsitems/qdeclarativeitem_p.h
index dae581c94f..3ad67c6b5e 100644
--- a/src/declarative/graphicsitems/qdeclarativeitem_p.h
+++ b/src/declarative/graphicsitems/qdeclarativeitem_p.h
@@ -382,7 +382,10 @@ class QDeclarativeKeyNavigationAttachedPrivate : public QObjectPrivate
{
public:
QDeclarativeKeyNavigationAttachedPrivate()
- : QObjectPrivate(), left(0), right(0), up(0), down(0), tab(0), backtab(0) {}
+ : QObjectPrivate(),
+ left(0), right(0), up(0), down(0), tab(0), backtab(0),
+ leftSet(false), rightSet(false), upSet(false), downSet(false),
+ tabSet(false), backtabSet(false) {}
QDeclarativeItem *left;
QDeclarativeItem *right;
@@ -390,6 +393,12 @@ public:
QDeclarativeItem *down;
QDeclarativeItem *tab;
QDeclarativeItem *backtab;
+ bool leftSet : 1;
+ bool rightSet : 1;
+ bool upSet : 1;
+ bool downSet : 1;
+ bool tabSet : 1;
+ bool backtabSet : 1;
};
class QDeclarativeKeyNavigationAttached : public QObject, public QDeclarativeItemKeyFilter
diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp
index af2c8f38d7..932e0740cd 100644
--- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp
+++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp
@@ -273,7 +273,6 @@ void QDeclarativeTextEdit::setText(const QString &text)
\o TextEdit.AutoText
\o TextEdit.PlainText
\o TextEdit.RichText
- \o TextEdit.StyledText
\endlist
The default is TextEdit.AutoText. If the text format is TextEdit.AutoText the text edit
@@ -1110,7 +1109,7 @@ void QDeclarativeTextEdit::setMouseSelectionMode(SelectionMode mode)
/*!
\qmlproperty bool TextEdit::readOnly
- Whether the user an interact with the TextEdit item. If this
+ Whether the user can interact with the TextEdit item. If this
property is set to true the text cannot be edited by user interaction.
By default this property is false.
diff --git a/src/declarative/items/checksync.pl b/src/declarative/items/checksync.pl
new file mode 100755
index 0000000000..26288bf1f4
--- /dev/null
+++ b/src/declarative/items/checksync.pl
@@ -0,0 +1,108 @@
+#!/usr/bin/perl
+#############################################################################
+##
+## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+## All rights reserved.
+## Contact: Nokia Corporation (qt-info@nokia.com)
+##
+## This file is part of the Declarative module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## No Commercial Usage
+## This file contains pre-release code and may not be distributed.
+## You may use this file in accordance with the terms and conditions
+## contained in the Technology Preview License Agreement accompanying
+## this package.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 2.1 requirements
+## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## In addition, as a special exception, Nokia gives you certain additional
+## rights. These rights are described in the Nokia Qt LGPL Exception
+## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+##
+## If you have questions regarding the use of this file, please contact
+## Nokia at qt-info@nokia.com.
+##
+##
+##
+##
+##
+##
+##
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+use strict;
+use warnings;
+
+die "Usage: $0 <QML directory>" if (@ARGV != 1);
+
+my @excludes;
+open (SYNCEXCLUDES, "<", "syncexcludes");
+while (<SYNCEXCLUDES>) {
+ if (/^([a-zA-Z0-9\._]+)/) {
+ my $exclude = $1;
+ push (@excludes, $exclude);
+ }
+}
+
+my $portdir = ".";
+my $qmldir = $ARGV[0];
+
+opendir (PORTDIR, $portdir) or die "Cannot open port directory";
+opendir (QMLDIR, $qmldir) or die "Cannot open QML directory";
+
+my @portfiles = readdir(PORTDIR);
+my @qmlfiles = readdir(QMLDIR);
+
+closedir(PORTDIR);
+closedir(QMLDIR);
+
+foreach my $qmlfile (@qmlfiles) {
+ if ($qmlfile =~ /^qdeclarative.*\.cpp$/ or $qmlfile =~ /qdeclarative.*\.h$/) {
+
+ if (grep { $_ eq $qmlfile} @excludes) {
+ next;
+ }
+
+ my $portfile = $qmlfile;
+ $portfile =~ s/^qdeclarative/qsg/;
+
+ if (grep { $_ eq $portfile} @portfiles) {
+
+ open (PORTFILE, "<", "$portdir/$portfile") or die("Cannot open $portdir/$portfile for reading");
+
+ my $firstline = <PORTFILE>;
+
+ close (PORTFILE);
+
+ if ($firstline and $firstline =~ /^\/\/ Commit: ([a-z0-9]+)/) {
+ my $sha1 = $1;
+ my $commitSha1 = "";
+
+ my $output = `cd $qmldir; git log $qmlfile | head -n 1`;
+ if ($output =~ /commit ([a-z0-9]+)/) {
+ $commitSha1 = $1;
+ }
+
+ if ($commitSha1 eq $sha1) {
+ print ("$portfile: OK\n");
+ } else {
+ print ("$portfile: OUT OF DATE\n");
+ }
+ } else {
+ print ("$portfile: OUT OF DATE\n");
+ }
+ } else {
+ print ("$portfile: MISSING\n");
+ }
+ }
+}
diff --git a/src/declarative/items/items.pri b/src/declarative/items/items.pri
new file mode 100644
index 0000000000..3dbb4fa910
--- /dev/null
+++ b/src/declarative/items/items.pri
@@ -0,0 +1,109 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qsgevents_p_p.h \
+ $$PWD/qsgitemchangelistener_p.h \
+ $$PWD/qsganchors_p.h \
+ $$PWD/qsganchors_p_p.h \
+ $$PWD/qsgitem.h \
+ $$PWD/qsgitem_p.h \
+ $$PWD/qsgrectangle_p.h \
+ $$PWD/qsgrectangle_p_p.h \
+ $$PWD/qsgcanvas.h \
+ $$PWD/qsgcanvas_p.h \
+ $$PWD/qsgfocusscope_p.h \
+ $$PWD/qsgitemsmodule_p.h \
+ $$PWD/qsgpainteditem.h \
+ $$PWD/qsgpainteditem_p.h \
+ $$PWD/qsgtext_p.h \
+ $$PWD/qsgtext_p_p.h \
+ $$PWD/qsgtextnode_p.h \
+ $$PWD/qsgtextinput_p.h \
+ $$PWD/qsgtextinput_p_p.h \
+ $$PWD/qsgtextedit_p.h \
+ $$PWD/qsgtextedit_p_p.h \
+ $$PWD/qsgimagebase_p.h \
+ $$PWD/qsgimagebase_p_p.h \
+ $$PWD/qsgimage_p.h \
+ $$PWD/qsgimage_p_p.h \
+ $$PWD/qsgborderimage_p.h \
+ $$PWD/qsgborderimage_p_p.h \
+ $$PWD/qsgninepatchnode_p.h \
+ $$PWD/qsgscalegrid_p_p.h \
+ $$PWD/qsgmousearea_p.h \
+ $$PWD/qsgmousearea_p_p.h \
+ $$PWD/qsgpincharea_p.h \
+ $$PWD/qsgpincharea_p_p.h \
+ $$PWD/qsgflickable_p.h \
+ $$PWD/qsgflickable_p_p.h \
+ $$PWD/qsglistview_p.h \
+ $$PWD/qsgvisualitemmodel_p.h \
+ $$PWD/qsgrepeater_p.h \
+ $$PWD/qsgrepeater_p_p.h \
+ $$PWD/qsggridview_p.h \
+ $$PWD/qsgpathview_p.h \
+ $$PWD/qsgpathview_p_p.h \
+ $$PWD/qsgpositioners_p.h \
+ $$PWD/qsgpositioners_p_p.h \
+ $$PWD/qsgloader_p.h \
+ $$PWD/qsgloader_p_p.h \
+ $$PWD/qsganimatedimage_p.h \
+ $$PWD/qsganimatedimage_p_p.h \
+ $$PWD/qsgflipable_p.h \
+ $$PWD/qsgtranslate_p.h \
+ $$PWD/qsgclipnode_p.h \
+ $$PWD/qsgview.h \
+ $$PWD/qsganimation_p.h \
+ $$PWD/qsganimation_p_p.h \
+ $$PWD/qsgstateoperations_p.h \
+ $$PWD/qsgimplicitsizeitem_p.h \
+ $$PWD/qsgimplicitsizeitem_p_p.h \
+
+SOURCES += \
+ $$PWD/qsgevents.cpp \
+ $$PWD/qsganchors.cpp \
+ $$PWD/qsgitem.cpp \
+ $$PWD/qsgrectangle.cpp \
+ $$PWD/qsgcanvas.cpp \
+ $$PWD/qsgfocusscope.cpp \
+ $$PWD/qsgitemsmodule.cpp \
+ $$PWD/qsgpainteditem.cpp \
+ $$PWD/qsgtext.cpp \
+ $$PWD/qsgtextnode.cpp \
+ $$PWD/qsgtextinput.cpp \
+ $$PWD/qsgtextedit.cpp \
+ $$PWD/qsgimagebase.cpp \
+ $$PWD/qsgimage.cpp \
+ $$PWD/qsgborderimage.cpp \
+ $$PWD/qsgninepatchnode.cpp \
+ $$PWD/qsgscalegrid.cpp \
+ $$PWD/qsgmousearea.cpp \
+ $$PWD/qsgpincharea.cpp \
+ $$PWD/qsgflickable.cpp \
+ $$PWD/qsglistview.cpp \
+ $$PWD/qsgvisualitemmodel.cpp \
+ $$PWD/qsgrepeater.cpp \
+ $$PWD/qsggridview.cpp \
+ $$PWD/qsgpathview.cpp \
+ $$PWD/qsgpositioners.cpp \
+ $$PWD/qsgloader.cpp \
+ $$PWD/qsganimatedimage.cpp \
+ $$PWD/qsgflipable.cpp \
+ $$PWD/qsgtranslate.cpp \
+ $$PWD/qsgclipnode.cpp \
+ $$PWD/qsgview.cpp \
+ $$PWD/qsganimation.cpp \
+ $$PWD/qsgstateoperations.cpp \
+ $$PWD/qsgimplicitsizeitem.cpp \
+
+SOURCES += \
+ $$PWD/qsgshadereffectitem.cpp \
+ $$PWD/qsgshadereffectmesh.cpp \
+ $$PWD/qsgshadereffectnode.cpp \
+ $$PWD/qsgshadereffectsource.cpp \
+
+HEADERS += \
+ $$PWD/qsgshadereffectitem_p.h \
+ $$PWD/qsgshadereffectmesh_p.h \
+ $$PWD/qsgshadereffectnode_p.h \
+ $$PWD/qsgshadereffectsource_p.h \
diff --git a/src/declarative/items/qsganchors.cpp b/src/declarative/items/qsganchors.cpp
new file mode 100644
index 0000000000..ff9351edbc
--- /dev/null
+++ b/src/declarative/items/qsganchors.cpp
@@ -0,0 +1,1111 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsganchors_p_p.h"
+
+#include "qsgitem.h"
+#include "qsgitem_p.h"
+
+#include <qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+//TODO: should we cache relationships, so we don't have to check each time (parent-child or sibling)?
+//TODO: support non-parent, non-sibling (need to find lowest common ancestor)
+
+static qreal hcenter(QSGItem *item)
+{
+ qreal width = item->width();
+ int iw = width;
+ if (iw % 2)
+ return (width + 1) / 2;
+ else
+ return width / 2;
+}
+
+static qreal vcenter(QSGItem *item)
+{
+ qreal height = item->height();
+ int ih = height;
+ if (ih % 2)
+ return (height + 1) / 2;
+ else
+ return height / 2;
+}
+
+//### const item?
+//local position
+static qreal position(QSGItem *item, QSGAnchorLine::AnchorLine anchorLine)
+{
+ qreal ret = 0.0;
+ switch(anchorLine) {
+ case QSGAnchorLine::Left:
+ ret = item->x();
+ break;
+ case QSGAnchorLine::Right:
+ ret = item->x() + item->width();
+ break;
+ case QSGAnchorLine::Top:
+ ret = item->y();
+ break;
+ case QSGAnchorLine::Bottom:
+ ret = item->y() + item->height();
+ break;
+ case QSGAnchorLine::HCenter:
+ ret = item->x() + hcenter(item);
+ break;
+ case QSGAnchorLine::VCenter:
+ ret = item->y() + vcenter(item);
+ break;
+ case QSGAnchorLine::Baseline:
+ ret = item->y() + item->baselineOffset();
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+//position when origin is 0,0
+static qreal adjustedPosition(QSGItem *item, QSGAnchorLine::AnchorLine anchorLine)
+{
+ qreal ret = 0.0;
+ switch(anchorLine) {
+ case QSGAnchorLine::Left:
+ ret = 0.0;
+ break;
+ case QSGAnchorLine::Right:
+ ret = item->width();
+ break;
+ case QSGAnchorLine::Top:
+ ret = 0.0;
+ break;
+ case QSGAnchorLine::Bottom:
+ ret = item->height();
+ break;
+ case QSGAnchorLine::HCenter:
+ ret = hcenter(item);
+ break;
+ case QSGAnchorLine::VCenter:
+ ret = vcenter(item);
+ break;
+ case QSGAnchorLine::Baseline:
+ ret = item->baselineOffset();
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+QSGAnchors::QSGAnchors(QSGItem *item, QObject *parent)
+: QObject(*new QSGAnchorsPrivate(item), parent)
+{
+}
+
+QSGAnchors::~QSGAnchors()
+{
+ Q_D(QSGAnchors);
+ d->remDepend(d->fill);
+ d->remDepend(d->centerIn);
+ d->remDepend(d->left.item);
+ d->remDepend(d->right.item);
+ d->remDepend(d->top.item);
+ d->remDepend(d->bottom.item);
+ d->remDepend(d->vCenter.item);
+ d->remDepend(d->hCenter.item);
+ d->remDepend(d->baseline.item);
+}
+
+void QSGAnchorsPrivate::fillChanged()
+{
+ Q_Q(QSGAnchors);
+ if (!fill || !isItemComplete())
+ return;
+
+ if (updatingFill < 2) {
+ ++updatingFill;
+
+ qreal horizontalMargin = q->mirrored() ? rightMargin : leftMargin;
+
+ if (fill == item->parentItem()) { //child-parent
+ setItemPos(QPointF(horizontalMargin, topMargin));
+ } else if (fill->parentItem() == item->parentItem()) { //siblings
+ setItemPos(QPointF(fill->x()+horizontalMargin, fill->y()+topMargin));
+ }
+ setItemSize(QSizeF(fill->width()-leftMargin-rightMargin, fill->height()-topMargin-bottomMargin));
+
+ --updatingFill;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << QSGAnchors::tr("Possible anchor loop detected on fill.");
+ }
+
+}
+
+void QSGAnchorsPrivate::centerInChanged()
+{
+ Q_Q(QSGAnchors);
+ if (!centerIn || fill || !isItemComplete())
+ return;
+
+ if (updatingCenterIn < 2) {
+ ++updatingCenterIn;
+
+ qreal effectiveHCenterOffset = q->mirrored() ? -hCenterOffset : hCenterOffset;
+ if (centerIn == item->parentItem()) {
+ QPointF p(hcenter(item->parentItem()) - hcenter(item) + effectiveHCenterOffset,
+ vcenter(item->parentItem()) - vcenter(item) + vCenterOffset);
+ setItemPos(p);
+
+ } else if (centerIn->parentItem() == item->parentItem()) {
+ QPointF p(centerIn->x() + hcenter(centerIn) - hcenter(item) + effectiveHCenterOffset,
+ centerIn->y() + vcenter(centerIn) - vcenter(item) + vCenterOffset);
+ setItemPos(p);
+ }
+
+ --updatingCenterIn;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << QSGAnchors::tr("Possible anchor loop detected on centerIn.");
+ }
+}
+
+void QSGAnchorsPrivate::clearItem(QSGItem *item)
+{
+ if (!item)
+ return;
+ if (fill == item)
+ fill = 0;
+ if (centerIn == item)
+ centerIn = 0;
+ if (left.item == item) {
+ left.item = 0;
+ usedAnchors &= ~QSGAnchors::LeftAnchor;
+ }
+ if (right.item == item) {
+ right.item = 0;
+ usedAnchors &= ~QSGAnchors::RightAnchor;
+ }
+ if (top.item == item) {
+ top.item = 0;
+ usedAnchors &= ~QSGAnchors::TopAnchor;
+ }
+ if (bottom.item == item) {
+ bottom.item = 0;
+ usedAnchors &= ~QSGAnchors::BottomAnchor;
+ }
+ if (vCenter.item == item) {
+ vCenter.item = 0;
+ usedAnchors &= ~QSGAnchors::VCenterAnchor;
+ }
+ if (hCenter.item == item) {
+ hCenter.item = 0;
+ usedAnchors &= ~QSGAnchors::HCenterAnchor;
+ }
+ if (baseline.item == item) {
+ baseline.item = 0;
+ usedAnchors &= ~QSGAnchors::BaselineAnchor;
+ }
+}
+
+void QSGAnchorsPrivate::addDepend(QSGItem *item)
+{
+ if (!item)
+ return;
+
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+ p->addItemChangeListener(this, QSGItemPrivate::Geometry);
+}
+
+void QSGAnchorsPrivate::remDepend(QSGItem *item)
+{
+ if (!item)
+ return;
+
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+ p->removeItemChangeListener(this, QSGItemPrivate::Geometry);
+}
+
+bool QSGAnchors::mirrored()
+{
+ Q_D(QSGAnchors);
+ return QSGItemPrivate::get(d->item)->effectiveLayoutMirror;
+}
+
+bool QSGAnchorsPrivate::isItemComplete() const
+{
+ return componentComplete;
+}
+
+void QSGAnchors::classBegin()
+{
+ Q_D(QSGAnchors);
+ d->componentComplete = false;
+}
+
+void QSGAnchors::componentComplete()
+{
+ Q_D(QSGAnchors);
+ d->componentComplete = true;
+}
+
+void QSGAnchorsPrivate::setItemHeight(qreal v)
+{
+ updatingMe = true;
+ item->setHeight(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::setItemWidth(qreal v)
+{
+ updatingMe = true;
+ item->setWidth(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::setItemX(qreal v)
+{
+ updatingMe = true;
+ item->setX(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::setItemY(qreal v)
+{
+ updatingMe = true;
+ item->setY(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::setItemPos(const QPointF &v)
+{
+ updatingMe = true;
+ item->setPos(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::setItemSize(const QSizeF &v)
+{
+ updatingMe = true;
+ item->setSize(v);
+ updatingMe = false;
+}
+
+void QSGAnchorsPrivate::updateMe()
+{
+ if (updatingMe) {
+ updatingMe = false;
+ return;
+ }
+
+ fillChanged();
+ centerInChanged();
+ updateHorizontalAnchors();
+ updateVerticalAnchors();
+}
+
+void QSGAnchorsPrivate::updateOnComplete()
+{
+ fillChanged();
+ centerInChanged();
+ updateHorizontalAnchors();
+ updateVerticalAnchors();
+}
+
+void QSGAnchorsPrivate::itemGeometryChanged(QSGItem *, const QRectF &newG, const QRectF &oldG)
+{
+ fillChanged();
+ centerInChanged();
+ if (newG.x() != oldG.x() || newG.width() != oldG.width())
+ updateHorizontalAnchors();
+ if (newG.y() != oldG.y() || newG.height() != oldG.height())
+ updateVerticalAnchors();
+}
+
+QSGItem *QSGAnchors::fill() const
+{
+ Q_D(const QSGAnchors);
+ return d->fill;
+}
+
+void QSGAnchors::setFill(QSGItem *f)
+{
+ Q_D(QSGAnchors);
+ if (d->fill == f)
+ return;
+
+ if (!f) {
+ d->remDepend(d->fill);
+ d->fill = f;
+ emit fillChanged();
+ return;
+ }
+ if (f != d->item->parentItem() && f->parentItem() != d->item->parentItem()){
+ qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling.");
+ return;
+ }
+ d->remDepend(d->fill);
+ d->fill = f;
+ d->addDepend(d->fill);
+ emit fillChanged();
+ d->fillChanged();
+}
+
+void QSGAnchors::resetFill()
+{
+ setFill(0);
+}
+
+QSGItem *QSGAnchors::centerIn() const
+{
+ Q_D(const QSGAnchors);
+ return d->centerIn;
+}
+
+void QSGAnchors::setCenterIn(QSGItem* c)
+{
+ Q_D(QSGAnchors);
+ if (d->centerIn == c)
+ return;
+
+ if (!c) {
+ d->remDepend(d->centerIn);
+ d->centerIn = c;
+ emit centerInChanged();
+ return;
+ }
+ if (c != d->item->parentItem() && c->parentItem() != d->item->parentItem()){
+ qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling.");
+ return;
+ }
+
+ d->remDepend(d->centerIn);
+ d->centerIn = c;
+ d->addDepend(d->centerIn);
+ emit centerInChanged();
+ d->centerInChanged();
+}
+
+void QSGAnchors::resetCenterIn()
+{
+ setCenterIn(0);
+}
+
+bool QSGAnchorsPrivate::calcStretch(const QSGAnchorLine &edge1,
+ const QSGAnchorLine &edge2,
+ qreal offset1,
+ qreal offset2,
+ QSGAnchorLine::AnchorLine line,
+ qreal &stretch)
+{
+ bool edge1IsParent = (edge1.item == item->parentItem());
+ bool edge2IsParent = (edge2.item == item->parentItem());
+ bool edge1IsSibling = (edge1.item->parentItem() == item->parentItem());
+ bool edge2IsSibling = (edge2.item->parentItem() == item->parentItem());
+
+ bool invalid = false;
+ if ((edge2IsParent && edge1IsParent) || (edge2IsSibling && edge1IsSibling)) {
+ stretch = (position(edge2.item, edge2.anchorLine) + offset2)
+ - (position(edge1.item, edge1.anchorLine) + offset1);
+ } else if (edge2IsParent && edge1IsSibling) {
+ stretch = (position(edge2.item, edge2.anchorLine) + offset2)
+ - (position(item->parentItem(), line)
+ + position(edge1.item, edge1.anchorLine) + offset1);
+ } else if (edge2IsSibling && edge1IsParent) {
+ stretch = (position(item->parentItem(), line) + position(edge2.item, edge2.anchorLine) + offset2)
+ - (position(edge1.item, edge1.anchorLine) + offset1);
+ } else
+ invalid = true;
+
+ return invalid;
+}
+
+void QSGAnchorsPrivate::updateVerticalAnchors()
+{
+ if (fill || centerIn || !isItemComplete())
+ return;
+
+ if (updatingVerticalAnchor < 2) {
+ ++updatingVerticalAnchor;
+ if (usedAnchors & QSGAnchors::TopAnchor) {
+ //Handle stretching
+ bool invalid = true;
+ qreal height = 0.0;
+ if (usedAnchors & QSGAnchors::BottomAnchor) {
+ invalid = calcStretch(top, bottom, topMargin, -bottomMargin, QSGAnchorLine::Top, height);
+ } else if (usedAnchors & QSGAnchors::VCenterAnchor) {
+ invalid = calcStretch(top, vCenter, topMargin, vCenterOffset, QSGAnchorLine::Top, height);
+ height *= 2;
+ }
+ if (!invalid)
+ setItemHeight(height);
+
+ //Handle top
+ if (top.item == item->parentItem()) {
+ setItemY(adjustedPosition(top.item, top.anchorLine) + topMargin);
+ } else if (top.item->parentItem() == item->parentItem()) {
+ setItemY(position(top.item, top.anchorLine) + topMargin);
+ }
+ } else if (usedAnchors & QSGAnchors::BottomAnchor) {
+ //Handle stretching (top + bottom case is handled above)
+ if (usedAnchors & QSGAnchors::VCenterAnchor) {
+ qreal height = 0.0;
+ bool invalid = calcStretch(vCenter, bottom, vCenterOffset, -bottomMargin,
+ QSGAnchorLine::Top, height);
+ if (!invalid)
+ setItemHeight(height*2);
+ }
+
+ //Handle bottom
+ if (bottom.item == item->parentItem()) {
+ setItemY(adjustedPosition(bottom.item, bottom.anchorLine) - item->height() - bottomMargin);
+ } else if (bottom.item->parentItem() == item->parentItem()) {
+ setItemY(position(bottom.item, bottom.anchorLine) - item->height() - bottomMargin);
+ }
+ } else if (usedAnchors & QSGAnchors::VCenterAnchor) {
+ //(stetching handled above)
+
+ //Handle vCenter
+ if (vCenter.item == item->parentItem()) {
+ setItemY(adjustedPosition(vCenter.item, vCenter.anchorLine)
+ - vcenter(item) + vCenterOffset);
+ } else if (vCenter.item->parentItem() == item->parentItem()) {
+ setItemY(position(vCenter.item, vCenter.anchorLine) - vcenter(item) + vCenterOffset);
+ }
+ } else if (usedAnchors & QSGAnchors::BaselineAnchor) {
+ //Handle baseline
+ if (baseline.item == item->parentItem()) {
+ setItemY(adjustedPosition(baseline.item, baseline.anchorLine) - item->baselineOffset() + baselineOffset);
+ } else if (baseline.item->parentItem() == item->parentItem()) {
+ setItemY(position(baseline.item, baseline.anchorLine) - item->baselineOffset() + baselineOffset);
+ }
+ }
+ --updatingVerticalAnchor;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << QSGAnchors::tr("Possible anchor loop detected on vertical anchor.");
+ }
+}
+
+inline QSGAnchorLine::AnchorLine reverseAnchorLine(QSGAnchorLine::AnchorLine anchorLine)
+{
+ if (anchorLine == QSGAnchorLine::Left) {
+ return QSGAnchorLine::Right;
+ } else if (anchorLine == QSGAnchorLine::Right) {
+ return QSGAnchorLine::Left;
+ } else {
+ return anchorLine;
+ }
+}
+
+void QSGAnchorsPrivate::updateHorizontalAnchors()
+{
+ Q_Q(QSGAnchors);
+ if (fill || centerIn || !isItemComplete())
+ return;
+
+ if (updatingHorizontalAnchor < 3) {
+ ++updatingHorizontalAnchor;
+ qreal effectiveRightMargin, effectiveLeftMargin, effectiveHorizontalCenterOffset;
+ QSGAnchorLine effectiveLeft, effectiveRight, effectiveHorizontalCenter;
+ QSGAnchors::Anchor effectiveLeftAnchor, effectiveRightAnchor;
+ if (q->mirrored()) {
+ effectiveLeftAnchor = QSGAnchors::RightAnchor;
+ effectiveRightAnchor = QSGAnchors::LeftAnchor;
+ effectiveLeft.item = right.item;
+ effectiveLeft.anchorLine = reverseAnchorLine(right.anchorLine);
+ effectiveRight.item = left.item;
+ effectiveRight.anchorLine = reverseAnchorLine(left.anchorLine);
+ effectiveHorizontalCenter.item = hCenter.item;
+ effectiveHorizontalCenter.anchorLine = reverseAnchorLine(hCenter.anchorLine);
+ effectiveLeftMargin = rightMargin;
+ effectiveRightMargin = leftMargin;
+ effectiveHorizontalCenterOffset = -hCenterOffset;
+ } else {
+ effectiveLeftAnchor = QSGAnchors::LeftAnchor;
+ effectiveRightAnchor = QSGAnchors::RightAnchor;
+ effectiveLeft = left;
+ effectiveRight = right;
+ effectiveHorizontalCenter = hCenter;
+ effectiveLeftMargin = leftMargin;
+ effectiveRightMargin = rightMargin;
+ effectiveHorizontalCenterOffset = hCenterOffset;
+ }
+
+ if (usedAnchors & effectiveLeftAnchor) {
+ //Handle stretching
+ bool invalid = true;
+ qreal width = 0.0;
+ if (usedAnchors & effectiveRightAnchor) {
+ invalid = calcStretch(effectiveLeft, effectiveRight, effectiveLeftMargin, -effectiveRightMargin, QSGAnchorLine::Left, width);
+ } else if (usedAnchors & QSGAnchors::HCenterAnchor) {
+ invalid = calcStretch(effectiveLeft, effectiveHorizontalCenter, effectiveLeftMargin, effectiveHorizontalCenterOffset, QSGAnchorLine::Left, width);
+ width *= 2;
+ }
+ if (!invalid)
+ setItemWidth(width);
+
+ //Handle left
+ if (effectiveLeft.item == item->parentItem()) {
+ setItemX(adjustedPosition(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin);
+ } else if (effectiveLeft.item->parentItem() == item->parentItem()) {
+ setItemX(position(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin);
+ }
+ } else if (usedAnchors & effectiveRightAnchor) {
+ //Handle stretching (left + right case is handled in updateLeftAnchor)
+ if (usedAnchors & QSGAnchors::HCenterAnchor) {
+ qreal width = 0.0;
+ bool invalid = calcStretch(effectiveHorizontalCenter, effectiveRight, effectiveHorizontalCenterOffset, -effectiveRightMargin,
+ QSGAnchorLine::Left, width);
+ if (!invalid)
+ setItemWidth(width*2);
+ }
+
+ //Handle right
+ if (effectiveRight.item == item->parentItem()) {
+ setItemX(adjustedPosition(effectiveRight.item, effectiveRight.anchorLine) - item->width() - effectiveRightMargin);
+ } else if (effectiveRight.item->parentItem() == item->parentItem()) {
+ setItemX(position(effectiveRight.item, effectiveRight.anchorLine) - item->width() - effectiveRightMargin);
+ }
+ } else if (usedAnchors & QSGAnchors::HCenterAnchor) {
+ //Handle hCenter
+ if (effectiveHorizontalCenter.item == item->parentItem()) {
+ setItemX(adjustedPosition(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset);
+ } else if (effectiveHorizontalCenter.item->parentItem() == item->parentItem()) {
+ setItemX(position(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset);
+ }
+ }
+ --updatingHorizontalAnchor;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << QSGAnchors::tr("Possible anchor loop detected on horizontal anchor.");
+ }
+}
+
+QSGAnchorLine QSGAnchors::top() const
+{
+ Q_D(const QSGAnchors);
+ return d->top;
+}
+
+void QSGAnchors::setTop(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkVAnchorValid(edge) || d->top == edge)
+ return;
+
+ d->usedAnchors |= TopAnchor;
+
+ if (!d->checkVValid()) {
+ d->usedAnchors &= ~TopAnchor;
+ return;
+ }
+
+ d->remDepend(d->top.item);
+ d->top = edge;
+ d->addDepend(d->top.item);
+ emit topChanged();
+ d->updateVerticalAnchors();
+}
+
+void QSGAnchors::resetTop()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~TopAnchor;
+ d->remDepend(d->top.item);
+ d->top = QSGAnchorLine();
+ emit topChanged();
+ d->updateVerticalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::bottom() const
+{
+ Q_D(const QSGAnchors);
+ return d->bottom;
+}
+
+void QSGAnchors::setBottom(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkVAnchorValid(edge) || d->bottom == edge)
+ return;
+
+ d->usedAnchors |= BottomAnchor;
+
+ if (!d->checkVValid()) {
+ d->usedAnchors &= ~BottomAnchor;
+ return;
+ }
+
+ d->remDepend(d->bottom.item);
+ d->bottom = edge;
+ d->addDepend(d->bottom.item);
+ emit bottomChanged();
+ d->updateVerticalAnchors();
+}
+
+void QSGAnchors::resetBottom()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~BottomAnchor;
+ d->remDepend(d->bottom.item);
+ d->bottom = QSGAnchorLine();
+ emit bottomChanged();
+ d->updateVerticalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::verticalCenter() const
+{
+ Q_D(const QSGAnchors);
+ return d->vCenter;
+}
+
+void QSGAnchors::setVerticalCenter(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkVAnchorValid(edge) || d->vCenter == edge)
+ return;
+
+ d->usedAnchors |= VCenterAnchor;
+
+ if (!d->checkVValid()) {
+ d->usedAnchors &= ~VCenterAnchor;
+ return;
+ }
+
+ d->remDepend(d->vCenter.item);
+ d->vCenter = edge;
+ d->addDepend(d->vCenter.item);
+ emit verticalCenterChanged();
+ d->updateVerticalAnchors();
+}
+
+void QSGAnchors::resetVerticalCenter()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~VCenterAnchor;
+ d->remDepend(d->vCenter.item);
+ d->vCenter = QSGAnchorLine();
+ emit verticalCenterChanged();
+ d->updateVerticalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::baseline() const
+{
+ Q_D(const QSGAnchors);
+ return d->baseline;
+}
+
+void QSGAnchors::setBaseline(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkVAnchorValid(edge) || d->baseline == edge)
+ return;
+
+ d->usedAnchors |= BaselineAnchor;
+
+ if (!d->checkVValid()) {
+ d->usedAnchors &= ~BaselineAnchor;
+ return;
+ }
+
+ d->remDepend(d->baseline.item);
+ d->baseline = edge;
+ d->addDepend(d->baseline.item);
+ emit baselineChanged();
+ d->updateVerticalAnchors();
+}
+
+void QSGAnchors::resetBaseline()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~BaselineAnchor;
+ d->remDepend(d->baseline.item);
+ d->baseline = QSGAnchorLine();
+ emit baselineChanged();
+ d->updateVerticalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::left() const
+{
+ Q_D(const QSGAnchors);
+ return d->left;
+}
+
+void QSGAnchors::setLeft(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkHAnchorValid(edge) || d->left == edge)
+ return;
+
+ d->usedAnchors |= LeftAnchor;
+
+ if (!d->checkHValid()) {
+ d->usedAnchors &= ~LeftAnchor;
+ return;
+ }
+
+ d->remDepend(d->left.item);
+ d->left = edge;
+ d->addDepend(d->left.item);
+ emit leftChanged();
+ d->updateHorizontalAnchors();
+}
+
+void QSGAnchors::resetLeft()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~LeftAnchor;
+ d->remDepend(d->left.item);
+ d->left = QSGAnchorLine();
+ emit leftChanged();
+ d->updateHorizontalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::right() const
+{
+ Q_D(const QSGAnchors);
+ return d->right;
+}
+
+void QSGAnchors::setRight(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkHAnchorValid(edge) || d->right == edge)
+ return;
+
+ d->usedAnchors |= RightAnchor;
+
+ if (!d->checkHValid()) {
+ d->usedAnchors &= ~RightAnchor;
+ return;
+ }
+
+ d->remDepend(d->right.item);
+ d->right = edge;
+ d->addDepend(d->right.item);
+ emit rightChanged();
+ d->updateHorizontalAnchors();
+}
+
+void QSGAnchors::resetRight()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~RightAnchor;
+ d->remDepend(d->right.item);
+ d->right = QSGAnchorLine();
+ emit rightChanged();
+ d->updateHorizontalAnchors();
+}
+
+QSGAnchorLine QSGAnchors::horizontalCenter() const
+{
+ Q_D(const QSGAnchors);
+ return d->hCenter;
+}
+
+void QSGAnchors::setHorizontalCenter(const QSGAnchorLine &edge)
+{
+ Q_D(QSGAnchors);
+ if (!d->checkHAnchorValid(edge) || d->hCenter == edge)
+ return;
+
+ d->usedAnchors |= HCenterAnchor;
+
+ if (!d->checkHValid()) {
+ d->usedAnchors &= ~HCenterAnchor;
+ return;
+ }
+
+ d->remDepend(d->hCenter.item);
+ d->hCenter = edge;
+ d->addDepend(d->hCenter.item);
+ emit horizontalCenterChanged();
+ d->updateHorizontalAnchors();
+}
+
+void QSGAnchors::resetHorizontalCenter()
+{
+ Q_D(QSGAnchors);
+ d->usedAnchors &= ~HCenterAnchor;
+ d->remDepend(d->hCenter.item);
+ d->hCenter = QSGAnchorLine();
+ emit horizontalCenterChanged();
+ d->updateHorizontalAnchors();
+}
+
+qreal QSGAnchors::leftMargin() const
+{
+ Q_D(const QSGAnchors);
+ return d->leftMargin;
+}
+
+void QSGAnchors::setLeftMargin(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->leftMargin == offset)
+ return;
+ d->leftMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateHorizontalAnchors();
+ emit leftMarginChanged();
+}
+
+qreal QSGAnchors::rightMargin() const
+{
+ Q_D(const QSGAnchors);
+ return d->rightMargin;
+}
+
+void QSGAnchors::setRightMargin(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->rightMargin == offset)
+ return;
+ d->rightMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateHorizontalAnchors();
+ emit rightMarginChanged();
+}
+
+qreal QSGAnchors::margins() const
+{
+ Q_D(const QSGAnchors);
+ return d->margins;
+}
+
+void QSGAnchors::setMargins(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->margins == offset)
+ return;
+ //###Is it significantly faster to set them directly so we can call fillChanged only once?
+ if(!d->rightMargin || d->rightMargin == d->margins)
+ setRightMargin(offset);
+ if(!d->leftMargin || d->leftMargin == d->margins)
+ setLeftMargin(offset);
+ if(!d->topMargin || d->topMargin == d->margins)
+ setTopMargin(offset);
+ if(!d->bottomMargin || d->bottomMargin == d->margins)
+ setBottomMargin(offset);
+ d->margins = offset;
+ emit marginsChanged();
+
+}
+
+qreal QSGAnchors::horizontalCenterOffset() const
+{
+ Q_D(const QSGAnchors);
+ return d->hCenterOffset;
+}
+
+void QSGAnchors::setHorizontalCenterOffset(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->hCenterOffset == offset)
+ return;
+ d->hCenterOffset = offset;
+ if(d->centerIn)
+ d->centerInChanged();
+ else
+ d->updateHorizontalAnchors();
+ emit horizontalCenterOffsetChanged();
+}
+
+qreal QSGAnchors::topMargin() const
+{
+ Q_D(const QSGAnchors);
+ return d->topMargin;
+}
+
+void QSGAnchors::setTopMargin(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->topMargin == offset)
+ return;
+ d->topMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateVerticalAnchors();
+ emit topMarginChanged();
+}
+
+qreal QSGAnchors::bottomMargin() const
+{
+ Q_D(const QSGAnchors);
+ return d->bottomMargin;
+}
+
+void QSGAnchors::setBottomMargin(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->bottomMargin == offset)
+ return;
+ d->bottomMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateVerticalAnchors();
+ emit bottomMarginChanged();
+}
+
+qreal QSGAnchors::verticalCenterOffset() const
+{
+ Q_D(const QSGAnchors);
+ return d->vCenterOffset;
+}
+
+void QSGAnchors::setVerticalCenterOffset(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->vCenterOffset == offset)
+ return;
+ d->vCenterOffset = offset;
+ if(d->centerIn)
+ d->centerInChanged();
+ else
+ d->updateVerticalAnchors();
+ emit verticalCenterOffsetChanged();
+}
+
+qreal QSGAnchors::baselineOffset() const
+{
+ Q_D(const QSGAnchors);
+ return d->baselineOffset;
+}
+
+void QSGAnchors::setBaselineOffset(qreal offset)
+{
+ Q_D(QSGAnchors);
+ if (d->baselineOffset == offset)
+ return;
+ d->baselineOffset = offset;
+ d->updateVerticalAnchors();
+ emit baselineOffsetChanged();
+}
+
+QSGAnchors::Anchors QSGAnchors::usedAnchors() const
+{
+ Q_D(const QSGAnchors);
+ return d->usedAnchors;
+}
+
+bool QSGAnchorsPrivate::checkHValid() const
+{
+ if (usedAnchors & QSGAnchors::LeftAnchor &&
+ usedAnchors & QSGAnchors::RightAnchor &&
+ usedAnchors & QSGAnchors::HCenterAnchor) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot specify left, right, and hcenter anchors.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QSGAnchorsPrivate::checkHAnchorValid(QSGAnchorLine anchor) const
+{
+ if (!anchor.item) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor to a null item.");
+ return false;
+ } else if (anchor.anchorLine & QSGAnchorLine::Vertical_Mask) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor a horizontal edge to a vertical edge.");
+ return false;
+ } else if (anchor.item != item->parentItem() && anchor.item->parentItem() != item->parentItem()){
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor to an item that isn't a parent or sibling.");
+ return false;
+ } else if (anchor.item == item) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor item to self.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QSGAnchorsPrivate::checkVValid() const
+{
+ if (usedAnchors & QSGAnchors::TopAnchor &&
+ usedAnchors & QSGAnchors::BottomAnchor &&
+ usedAnchors & QSGAnchors::VCenterAnchor) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot specify top, bottom, and vcenter anchors.");
+ return false;
+ } else if (usedAnchors & QSGAnchors::BaselineAnchor &&
+ (usedAnchors & QSGAnchors::TopAnchor ||
+ usedAnchors & QSGAnchors::BottomAnchor ||
+ usedAnchors & QSGAnchors::VCenterAnchor)) {
+ qmlInfo(item) << QSGAnchors::tr("Baseline anchor cannot be used in conjunction with top, bottom, or vcenter anchors.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QSGAnchorsPrivate::checkVAnchorValid(QSGAnchorLine anchor) const
+{
+ if (!anchor.item) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor to a null item.");
+ return false;
+ } else if (anchor.anchorLine & QSGAnchorLine::Horizontal_Mask) {
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor a vertical edge to a horizontal edge.");
+ return false;
+ } else if (anchor.item != item->parentItem() && anchor.item->parentItem() != item->parentItem()){
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor to an item that isn't a parent or sibling.");
+ return false;
+ } else if (anchor.item == item){
+ qmlInfo(item) << QSGAnchors::tr("Cannot anchor item to self.");
+ return false;
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include <moc_qsganchors_p.cpp>
+
diff --git a/src/declarative/items/qsganchors_p.h b/src/declarative/items/qsganchors_p.h
new file mode 100644
index 0000000000..d26fb57961
--- /dev/null
+++ b/src/declarative/items/qsganchors_p.h
@@ -0,0 +1,201 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANCHORS_P_H
+#define QSGANCHORS_P_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/QObject>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class QSGAnchorsPrivate;
+class QSGAnchorLine;
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGAnchors : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QSGAnchorLine left READ left WRITE setLeft RESET resetLeft NOTIFY leftChanged)
+ Q_PROPERTY(QSGAnchorLine right READ right WRITE setRight RESET resetRight NOTIFY rightChanged)
+ Q_PROPERTY(QSGAnchorLine horizontalCenter READ horizontalCenter WRITE setHorizontalCenter RESET resetHorizontalCenter NOTIFY horizontalCenterChanged)
+ Q_PROPERTY(QSGAnchorLine top READ top WRITE setTop RESET resetTop NOTIFY topChanged)
+ Q_PROPERTY(QSGAnchorLine bottom READ bottom WRITE setBottom RESET resetBottom NOTIFY bottomChanged)
+ Q_PROPERTY(QSGAnchorLine verticalCenter READ verticalCenter WRITE setVerticalCenter RESET resetVerticalCenter NOTIFY verticalCenterChanged)
+ Q_PROPERTY(QSGAnchorLine baseline READ baseline WRITE setBaseline RESET resetBaseline NOTIFY baselineChanged)
+ Q_PROPERTY(qreal margins READ margins WRITE setMargins NOTIFY marginsChanged)
+ Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
+ Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
+ Q_PROPERTY(qreal horizontalCenterOffset READ horizontalCenterOffset WRITE setHorizontalCenterOffset NOTIFY horizontalCenterOffsetChanged)
+ Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
+ Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
+ Q_PROPERTY(qreal verticalCenterOffset READ verticalCenterOffset WRITE setVerticalCenterOffset NOTIFY verticalCenterOffsetChanged)
+ Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged)
+ Q_PROPERTY(QSGItem *fill READ fill WRITE setFill RESET resetFill NOTIFY fillChanged)
+ Q_PROPERTY(QSGItem *centerIn READ centerIn WRITE setCenterIn RESET resetCenterIn NOTIFY centerInChanged)
+ Q_PROPERTY(bool mirrored READ mirrored NOTIFY mirroredChanged)
+
+public:
+ QSGAnchors(QSGItem *item, QObject *parent=0);
+ virtual ~QSGAnchors();
+
+ enum Anchor {
+ LeftAnchor = 0x01,
+ RightAnchor = 0x02,
+ TopAnchor = 0x04,
+ BottomAnchor = 0x08,
+ HCenterAnchor = 0x10,
+ VCenterAnchor = 0x20,
+ BaselineAnchor = 0x40,
+ Horizontal_Mask = LeftAnchor | RightAnchor | HCenterAnchor,
+ Vertical_Mask = TopAnchor | BottomAnchor | VCenterAnchor | BaselineAnchor
+ };
+ Q_DECLARE_FLAGS(Anchors, Anchor)
+
+ QSGAnchorLine left() const;
+ void setLeft(const QSGAnchorLine &edge);
+ void resetLeft();
+
+ QSGAnchorLine right() const;
+ void setRight(const QSGAnchorLine &edge);
+ void resetRight();
+
+ QSGAnchorLine horizontalCenter() const;
+ void setHorizontalCenter(const QSGAnchorLine &edge);
+ void resetHorizontalCenter();
+
+ QSGAnchorLine top() const;
+ void setTop(const QSGAnchorLine &edge);
+ void resetTop();
+
+ QSGAnchorLine bottom() const;
+ void setBottom(const QSGAnchorLine &edge);
+ void resetBottom();
+
+ QSGAnchorLine verticalCenter() const;
+ void setVerticalCenter(const QSGAnchorLine &edge);
+ void resetVerticalCenter();
+
+ QSGAnchorLine baseline() const;
+ void setBaseline(const QSGAnchorLine &edge);
+ void resetBaseline();
+
+ qreal leftMargin() const;
+ void setLeftMargin(qreal);
+
+ qreal rightMargin() const;
+ void setRightMargin(qreal);
+
+ qreal horizontalCenterOffset() const;
+ void setHorizontalCenterOffset(qreal);
+
+ qreal topMargin() const;
+ void setTopMargin(qreal);
+
+ qreal bottomMargin() const;
+ void setBottomMargin(qreal);
+
+ qreal margins() const;
+ void setMargins(qreal);
+
+ qreal verticalCenterOffset() const;
+ void setVerticalCenterOffset(qreal);
+
+ qreal baselineOffset() const;
+ void setBaselineOffset(qreal);
+
+ QSGItem *fill() const;
+ void setFill(QSGItem *);
+ void resetFill();
+
+ QSGItem *centerIn() const;
+ void setCenterIn(QSGItem *);
+ void resetCenterIn();
+
+ Anchors usedAnchors() const;
+
+ bool mirrored();
+
+ void classBegin();
+ void componentComplete();
+
+Q_SIGNALS:
+ void leftChanged();
+ void rightChanged();
+ void topChanged();
+ void bottomChanged();
+ void verticalCenterChanged();
+ void horizontalCenterChanged();
+ void baselineChanged();
+ void fillChanged();
+ void centerInChanged();
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void marginsChanged();
+ void verticalCenterOffsetChanged();
+ void horizontalCenterOffsetChanged();
+ void baselineOffsetChanged();
+ void mirroredChanged();
+
+private:
+ friend class QSGItemPrivate;
+ Q_DISABLE_COPY(QSGAnchors)
+ Q_DECLARE_PRIVATE(QSGAnchors)
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGAnchors::Anchors)
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGAnchors)
+
+QT_END_HEADER
+
+#endif // QSGANCHORS_P_H
diff --git a/src/declarative/items/qsganchors_p_p.h b/src/declarative/items/qsganchors_p_p.h
new file mode 100644
index 0000000000..cb9b950c8f
--- /dev/null
+++ b/src/declarative/items/qsganchors_p_p.h
@@ -0,0 +1,173 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANCHORS_P_P_H
+#define QSGANCHORS_P_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 "qsganchors_p.h"
+#include "qsgitemchangelistener_p.h"
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGAnchorLine
+{
+public:
+ QSGAnchorLine() : item(0), anchorLine(Invalid) {}
+
+ enum AnchorLine {
+ Invalid = 0x0,
+ Left = 0x01,
+ Right = 0x02,
+ Top = 0x04,
+ Bottom = 0x08,
+ HCenter = 0x10,
+ VCenter = 0x20,
+ Baseline = 0x40,
+ Horizontal_Mask = Left | Right | HCenter,
+ Vertical_Mask = Top | Bottom | VCenter | Baseline
+ };
+
+ QSGItem *item;
+ AnchorLine anchorLine;
+};
+
+inline bool operator==(const QSGAnchorLine& a, const QSGAnchorLine& b)
+{
+ return a.item == b.item && a.anchorLine == b.anchorLine;
+}
+
+class QSGAnchorsPrivate : public QObjectPrivate, public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGAnchors)
+public:
+ QSGAnchorsPrivate(QSGItem *i)
+ : componentComplete(true), updatingMe(false), updatingHorizontalAnchor(0),
+ updatingVerticalAnchor(0), updatingFill(0), updatingCenterIn(0), item(i), usedAnchors(0), fill(0),
+ centerIn(0), leftMargin(0), rightMargin(0), topMargin(0), bottomMargin(0),
+ margins(0), vCenterOffset(0), hCenterOffset(0), baselineOffset(0)
+ {
+ }
+
+ void clearItem(QSGItem *);
+
+ void addDepend(QSGItem *);
+ void remDepend(QSGItem *);
+ bool isItemComplete() const;
+
+ bool componentComplete:1;
+ bool updatingMe:1;
+ uint updatingHorizontalAnchor:2;
+ uint updatingVerticalAnchor:2;
+ uint updatingFill:2;
+ uint updatingCenterIn:2;
+
+ void setItemHeight(qreal);
+ void setItemWidth(qreal);
+ void setItemX(qreal);
+ void setItemY(qreal);
+ void setItemPos(const QPointF &);
+ void setItemSize(const QSizeF &);
+
+ void updateOnComplete();
+ void updateMe();
+
+ // QSGItemGeometryListener interface
+ void itemGeometryChanged(QSGItem *, const QRectF &, const QRectF &);
+ QSGAnchorsPrivate *anchorPrivate() { return this; }
+
+ bool checkHValid() const;
+ bool checkVValid() const;
+ bool checkHAnchorValid(QSGAnchorLine anchor) const;
+ bool checkVAnchorValid(QSGAnchorLine anchor) const;
+ bool calcStretch(const QSGAnchorLine &edge1, const QSGAnchorLine &edge2, qreal offset1, qreal offset2, QSGAnchorLine::AnchorLine line, qreal &stretch);
+
+ bool isMirrored() const;
+ void updateHorizontalAnchors();
+ void updateVerticalAnchors();
+ void fillChanged();
+ void centerInChanged();
+
+ QSGItem *item;
+ QSGAnchors::Anchors usedAnchors;
+
+ QSGItem *fill;
+ QSGItem *centerIn;
+
+ QSGAnchorLine left;
+ QSGAnchorLine right;
+ QSGAnchorLine top;
+ QSGAnchorLine bottom;
+ QSGAnchorLine vCenter;
+ QSGAnchorLine hCenter;
+ QSGAnchorLine baseline;
+
+ qreal leftMargin;
+ qreal rightMargin;
+ qreal topMargin;
+ qreal bottomMargin;
+ qreal margins;
+ qreal vCenterOffset;
+ qreal hCenterOffset;
+ qreal baselineOffset;
+
+ static inline QSGAnchorsPrivate *get(QSGAnchors *o) {
+ return static_cast<QSGAnchorsPrivate *>(QObjectPrivate::get(o));
+ }
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QSGAnchorLine)
+
+#endif
diff --git a/src/declarative/items/qsganimatedimage.cpp b/src/declarative/items/qsganimatedimage.cpp
new file mode 100644
index 0000000000..f036042ce2
--- /dev/null
+++ b/src/declarative/items/qsganimatedimage.cpp
@@ -0,0 +1,304 @@
+// Commit: af33f9f2e7ec433b81f5c18e3e7395db4a56c5fe
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsganimatedimage_p.h"
+#include "qsganimatedimage_p_p.h"
+
+#ifndef QT_NO_MOVIE
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qmovie.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkreply.h>
+
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGAnimatedImage::QSGAnimatedImage(QSGItem *parent)
+ : QSGImage(*(new QSGAnimatedImagePrivate), parent)
+{
+}
+
+QSGAnimatedImage::~QSGAnimatedImage()
+{
+ Q_D(QSGAnimatedImage);
+ delete d->_movie;
+}
+
+bool QSGAnimatedImage::isPaused() const
+{
+ Q_D(const QSGAnimatedImage);
+ if(!d->_movie)
+ return false;
+ return d->_movie->state()==QMovie::Paused;
+}
+
+void QSGAnimatedImage::setPaused(bool pause)
+{
+ Q_D(QSGAnimatedImage);
+ if(pause == d->paused)
+ return;
+ d->paused = pause;
+ if(!d->_movie)
+ return;
+ d->_movie->setPaused(pause);
+}
+
+bool QSGAnimatedImage::isPlaying() const
+{
+ Q_D(const QSGAnimatedImage);
+ if (!d->_movie)
+ return false;
+ return d->_movie->state()!=QMovie::NotRunning;
+}
+
+void QSGAnimatedImage::setPlaying(bool play)
+{
+ Q_D(QSGAnimatedImage);
+ if(play == d->playing)
+ return;
+ d->playing = play;
+ if (!d->_movie)
+ return;
+ if (play)
+ d->_movie->start();
+ else
+ d->_movie->stop();
+}
+
+int QSGAnimatedImage::currentFrame() const
+{
+ Q_D(const QSGAnimatedImage);
+ if (!d->_movie)
+ return d->preset_currentframe;
+ return d->_movie->currentFrameNumber();
+}
+
+void QSGAnimatedImage::setCurrentFrame(int frame)
+{
+ Q_D(QSGAnimatedImage);
+ if (!d->_movie) {
+ d->preset_currentframe = frame;
+ return;
+ }
+ d->_movie->jumpToFrame(frame);
+}
+
+int QSGAnimatedImage::frameCount() const
+{
+ Q_D(const QSGAnimatedImage);
+ if (!d->_movie)
+ return 0;
+ return d->_movie->frameCount();
+}
+
+void QSGAnimatedImage::setSource(const QUrl &url)
+{
+ Q_D(QSGAnimatedImage);
+ if (url == d->url)
+ return;
+
+ delete d->_movie;
+ d->_movie = 0;
+
+ if (d->reply) {
+ d->reply->deleteLater();
+ d->reply = 0;
+ }
+
+ d->url = url;
+ emit sourceChanged(d->url);
+
+ if (isComponentComplete())
+ load();
+}
+
+void QSGAnimatedImage::load()
+{
+ Q_D(QSGAnimatedImage);
+
+ QSGImageBase::Status oldStatus = d->status;
+ qreal oldProgress = d->progress;
+
+ if (d->url.isEmpty()) {
+ delete d->_movie;
+ d->setPixmap(QPixmap());
+ d->progress = 0;
+ d->status = Null;
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
+ if (d->progress != oldProgress)
+ emit progressChanged(d->progress);
+ } else {
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
+ if (!lf.isEmpty()) {
+ //### should be unified with movieRequestFinished
+ d->_movie = new QMovie(lf);
+ if (!d->_movie->isValid()){
+ qmlInfo(this) << "Error Reading Animated Image File " << d->url.toString();
+ delete d->_movie;
+ d->_movie = 0;
+ d->status = Error;
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
+ return;
+ }
+ connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
+ this, SLOT(playingStatusChanged()));
+ connect(d->_movie, SIGNAL(frameChanged(int)),
+ this, SLOT(movieUpdate()));
+ d->_movie->setCacheMode(QMovie::CacheAll);
+ if(d->playing)
+ d->_movie->start();
+ else
+ d->_movie->jumpToFrame(0);
+ if(d->paused)
+ d->_movie->setPaused(true);
+ d->setPixmap(d->_movie->currentPixmap());
+ d->status = Ready;
+ d->progress = 1.0;
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
+ if (d->progress != oldProgress)
+ emit progressChanged(d->progress);
+ return;
+ }
+#endif
+ d->status = Loading;
+ d->progress = 0;
+ emit statusChanged(d->status);
+ emit progressChanged(d->progress);
+ QNetworkRequest req(d->url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ d->reply = qmlEngine(this)->networkAccessManager()->get(req);
+ QObject::connect(d->reply, SIGNAL(finished()),
+ this, SLOT(movieRequestFinished()));
+ QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ }
+}
+
+#define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16
+
+void QSGAnimatedImage::movieRequestFinished()
+{
+ Q_D(QSGAnimatedImage);
+
+ d->redirectCount++;
+ if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = d->reply->url().resolved(redirect.toUrl());
+ d->reply->deleteLater();
+ d->reply = 0;
+ setSource(url);
+ return;
+ }
+ }
+ d->redirectCount=0;
+
+ d->_movie = new QMovie(d->reply);
+ if (!d->_movie->isValid()){
+#ifndef QT_NO_DEBUG_STREAM
+ qmlInfo(this) << "Error Reading Animated Image File " << d->url;
+#endif
+ delete d->_movie;
+ d->_movie = 0;
+ d->status = Error;
+ emit statusChanged(d->status);
+ return;
+ }
+ connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
+ this, SLOT(playingStatusChanged()));
+ connect(d->_movie, SIGNAL(frameChanged(int)),
+ this, SLOT(movieUpdate()));
+ d->_movie->setCacheMode(QMovie::CacheAll);
+ if(d->playing)
+ d->_movie->start();
+ if (d->paused || !d->playing) {
+ d->_movie->jumpToFrame(d->preset_currentframe);
+ d->preset_currentframe = 0;
+ }
+ if(d->paused)
+ d->_movie->setPaused(true);
+ d->setPixmap(d->_movie->currentPixmap());
+ d->status = Ready;
+ emit statusChanged(d->status);
+}
+
+void QSGAnimatedImage::movieUpdate()
+{
+ Q_D(QSGAnimatedImage);
+ d->setPixmap(d->_movie->currentPixmap());
+ emit frameChanged();
+}
+
+void QSGAnimatedImage::playingStatusChanged()
+{
+ Q_D(QSGAnimatedImage);
+ if((d->_movie->state() != QMovie::NotRunning) != d->playing){
+ d->playing = (d->_movie->state() != QMovie::NotRunning);
+ emit playingChanged();
+ }
+ if((d->_movie->state() == QMovie::Paused) != d->paused){
+ d->playing = (d->_movie->state() == QMovie::Paused);
+ emit pausedChanged();
+ }
+}
+
+void QSGAnimatedImage::componentComplete()
+{
+ Q_D(QSGAnimatedImage);
+ QSGItem::componentComplete(); // NOT QSGImage
+ if (d->url.isValid())
+ load();
+ if (!d->reply) {
+ setCurrentFrame(d->preset_currentframe);
+ d->preset_currentframe = 0;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_MOVIE
diff --git a/src/declarative/items/qsganimatedimage_p.h b/src/declarative/items/qsganimatedimage_p.h
new file mode 100644
index 0000000000..64319a0f0d
--- /dev/null
+++ b/src/declarative/items/qsganimatedimage_p.h
@@ -0,0 +1,117 @@
+// Commit: 80d0fe9cbd92288a08d5ced8767f1edb651dae37
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANIMATEDIMAGE_P_H
+#define QSGANIMATEDIMAGE_P_H
+
+#include "qsgimage_p.h"
+
+#ifndef QT_NO_MOVIE
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QMovie;
+class QSGAnimatedImagePrivate;
+
+class Q_AUTOTEST_EXPORT QSGAnimatedImage : public QSGImage
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged)
+ Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
+ Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY frameChanged)
+ Q_PROPERTY(int frameCount READ frameCount)
+
+ // read-only for AnimatedImage
+ Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged)
+
+public:
+ QSGAnimatedImage(QSGItem *parent=0);
+ ~QSGAnimatedImage();
+
+ bool isPlaying() const;
+ void setPlaying(bool play);
+
+ bool isPaused() const;
+ void setPaused(bool pause);
+
+ int currentFrame() const;
+ void setCurrentFrame(int frame);
+
+ int frameCount() const;
+
+ // Extends QSGImage's src property*/
+ virtual void setSource(const QUrl&);
+
+Q_SIGNALS:
+ void playingChanged();
+ void pausedChanged();
+ void frameChanged();
+ void sourceSizeChanged();
+
+private Q_SLOTS:
+ void movieUpdate();
+ void movieRequestFinished();
+ void playingStatusChanged();
+
+protected:
+ virtual void load();
+ void componentComplete();
+
+private:
+ Q_DISABLE_COPY(QSGAnimatedImage)
+ Q_DECLARE_PRIVATE(QSGAnimatedImage)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGAnimatedImage)
+
+QT_END_HEADER
+
+#endif // QT_NO_MOVIE
+
+#endif // QSGANIMATEDIMAGE_P_H
diff --git a/src/declarative/items/qsganimatedimage_p_p.h b/src/declarative/items/qsganimatedimage_p_p.h
new file mode 100644
index 0000000000..560c8c1d43
--- /dev/null
+++ b/src/declarative/items/qsganimatedimage_p_p.h
@@ -0,0 +1,88 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANIMATEDIMAGE_P_P_H
+#define QSGANIMATEDIMAGE_P_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 "qsgimage_p_p.h"
+
+#ifndef QT_NO_MOVIE
+
+QT_BEGIN_NAMESPACE
+
+class QMovie;
+class QNetworkReply;
+
+class QSGAnimatedImagePrivate : public QSGImagePrivate
+{
+ Q_DECLARE_PUBLIC(QSGAnimatedImage)
+
+public:
+ QSGAnimatedImagePrivate()
+ : playing(true), paused(false), preset_currentframe(0), _movie(0), reply(0), redirectCount(0)
+ {
+ }
+
+ bool playing;
+ bool paused;
+ int preset_currentframe;
+ QMovie *_movie;
+ QNetworkReply *reply;
+ int redirectCount;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_MOVIE
+
+#endif // QSGANIMATEDIMAGE_P_P_H
diff --git a/src/declarative/items/qsganimation.cpp b/src/declarative/items/qsganimation.cpp
new file mode 100644
index 0000000000..ad6ed030fd
--- /dev/null
+++ b/src/declarative/items/qsganimation.cpp
@@ -0,0 +1,442 @@
+// Commit: 91501cc9b542de644cd70098a6bc5ff738cdeb49
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsganimation_p.h"
+#include "qsganimation_p_p.h"
+#include "qsgstateoperations_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qsequentialanimationgroup.h>
+#include <QtCore/qparallelanimationgroup.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGParentAnimation::QSGParentAnimation(QObject *parent)
+ : QDeclarativeAnimationGroup(*(new QSGParentAnimationPrivate), parent)
+{
+ Q_D(QSGParentAnimation);
+ d->topLevelGroup = new QSequentialAnimationGroup;
+ QDeclarative_setParent_noEvent(d->topLevelGroup, this);
+
+ d->startAction = new QActionAnimation;
+ QDeclarative_setParent_noEvent(d->startAction, d->topLevelGroup);
+ d->topLevelGroup->addAnimation(d->startAction);
+
+ d->ag = new QParallelAnimationGroup;
+ QDeclarative_setParent_noEvent(d->ag, d->topLevelGroup);
+ d->topLevelGroup->addAnimation(d->ag);
+
+ d->endAction = new QActionAnimation;
+ QDeclarative_setParent_noEvent(d->endAction, d->topLevelGroup);
+ d->topLevelGroup->addAnimation(d->endAction);
+}
+
+QSGParentAnimation::~QSGParentAnimation()
+{
+}
+
+QSGItem *QSGParentAnimation::target() const
+{
+ Q_D(const QSGParentAnimation);
+ return d->target;
+}
+
+void QSGParentAnimation::setTarget(QSGItem *target)
+{
+ Q_D(QSGParentAnimation);
+ if (target == d->target)
+ return;
+
+ d->target = target;
+ emit targetChanged();
+}
+
+QSGItem *QSGParentAnimation::newParent() const
+{
+ Q_D(const QSGParentAnimation);
+ return d->newParent;
+}
+
+void QSGParentAnimation::setNewParent(QSGItem *newParent)
+{
+ Q_D(QSGParentAnimation);
+ if (newParent == d->newParent)
+ return;
+
+ d->newParent = newParent;
+ emit newParentChanged();
+}
+
+QSGItem *QSGParentAnimation::via() const
+{
+ Q_D(const QSGParentAnimation);
+ return d->via;
+}
+
+void QSGParentAnimation::setVia(QSGItem *via)
+{
+ Q_D(QSGParentAnimation);
+ if (via == d->via)
+ return;
+
+ d->via = via;
+ emit viaChanged();
+}
+
+//### mirrors same-named function in QSGItem
+QPointF QSGParentAnimationPrivate::computeTransformOrigin(QSGItem::TransformOrigin origin, qreal width, qreal height) const
+{
+ switch(origin) {
+ default:
+ case QSGItem::TopLeft:
+ return QPointF(0, 0);
+ case QSGItem::Top:
+ return QPointF(width / 2., 0);
+ case QSGItem::TopRight:
+ return QPointF(width, 0);
+ case QSGItem::Left:
+ return QPointF(0, height / 2.);
+ case QSGItem::Center:
+ return QPointF(width / 2., height / 2.);
+ case QSGItem::Right:
+ return QPointF(width, height / 2.);
+ case QSGItem::BottomLeft:
+ return QPointF(0, height);
+ case QSGItem::Bottom:
+ return QPointF(width / 2., height);
+ case QSGItem::BottomRight:
+ return QPointF(width, height);
+ }
+}
+
+void QSGParentAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QSGParentAnimation);
+
+ struct QSGParentAnimationData : public QAbstractAnimationAction
+ {
+ QSGParentAnimationData() {}
+ ~QSGParentAnimationData() { qDeleteAll(pc); }
+
+ QDeclarativeStateActions actions;
+ //### reverse should probably apply on a per-action basis
+ bool reverse;
+ QList<QSGParentChange *> pc;
+ virtual void doAction()
+ {
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ const QDeclarativeAction &action = actions.at(ii);
+ if (reverse)
+ action.event->reverse();
+ else
+ action.event->execute();
+ }
+ }
+ };
+
+ QSGParentAnimationData *data = new QSGParentAnimationData;
+ QSGParentAnimationData *viaData = new QSGParentAnimationData;
+
+ bool hasExplicit = false;
+ if (d->target && d->newParent) {
+ data->reverse = false;
+ QDeclarativeAction myAction;
+ QSGParentChange *pc = new QSGParentChange;
+ pc->setObject(d->target);
+ pc->setParent(d->newParent);
+ myAction.event = pc;
+ data->pc << pc;
+ data->actions << myAction;
+ hasExplicit = true;
+ if (d->via) {
+ viaData->reverse = false;
+ QDeclarativeAction myVAction;
+ QSGParentChange *vpc = new QSGParentChange;
+ vpc->setObject(d->target);
+ vpc->setParent(d->via);
+ myVAction.event = vpc;
+ viaData->pc << vpc;
+ viaData->actions << myVAction;
+ }
+ //### once actions have concept of modified,
+ // loop to match appropriate ParentChanges and mark as modified
+ }
+
+ if (!hasExplicit)
+ for (int i = 0; i < actions.size(); ++i) {
+ QDeclarativeAction &action = actions[i];
+ if (action.event && action.event->typeName() == QLatin1String("ParentChange")
+ && (!d->target || static_cast<QSGParentChange*>(action.event)->object() == d->target)) {
+
+ QSGParentChange *pc = static_cast<QSGParentChange*>(action.event);
+ QDeclarativeAction myAction = action;
+ data->reverse = action.reverseEvent;
+
+ //### this logic differs from PropertyAnimation
+ // (probably a result of modified vs. done)
+ if (d->newParent) {
+ QSGParentChange *epc = new QSGParentChange;
+ epc->setObject(static_cast<QSGParentChange*>(action.event)->object());
+ epc->setParent(d->newParent);
+ myAction.event = epc;
+ data->pc << epc;
+ data->actions << myAction;
+ pc = epc;
+ } else {
+ action.actionDone = true;
+ data->actions << myAction;
+ }
+
+ if (d->via) {
+ viaData->reverse = false;
+ QDeclarativeAction myAction;
+ QSGParentChange *vpc = new QSGParentChange;
+ vpc->setObject(pc->object());
+ vpc->setParent(d->via);
+ myAction.event = vpc;
+ viaData->pc << vpc;
+ viaData->actions << myAction;
+ QDeclarativeAction dummyAction;
+ QDeclarativeAction &xAction = pc->xIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
+ QDeclarativeAction &yAction = pc->yIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
+ QDeclarativeAction &sAction = pc->scaleIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
+ QDeclarativeAction &rAction = pc->rotationIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
+ QSGItem *target = pc->object();
+ QSGItem *targetParent = action.reverseEvent ? pc->originalParent() : pc->parent();
+
+ //### this mirrors the logic in QSGParentChange.
+ bool ok;
+ const QTransform &transform = targetParent->itemTransform(d->via, &ok);
+ if (transform.type() >= QTransform::TxShear || !ok) {
+ qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under complex transform");
+ ok = false;
+ }
+
+ qreal scale = 1;
+ qreal rotation = 0;
+ bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
+ if (ok && !isRotate) {
+ if (transform.m11() == transform.m22())
+ scale = transform.m11();
+ else {
+ qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under non-uniform scale");
+ ok = false;
+ }
+ } else if (ok && isRotate) {
+ if (transform.m11() == transform.m22())
+ scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
+ else {
+ qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under non-uniform scale");
+ ok = false;
+ }
+
+ if (scale != 0)
+ rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI;
+ else {
+ qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under scale of 0");
+ ok = false;
+ }
+ }
+
+ const QPointF &point = transform.map(QPointF(xAction.toValue.toReal(),yAction.toValue.toReal()));
+ qreal x = point.x();
+ qreal y = point.y();
+ if (ok && target->transformOrigin() != QSGItem::TopLeft) {
+ qreal w = target->width();
+ qreal h = target->height();
+ if (pc->widthIsSet() && i < actions.size() - 1)
+ w = actions[++i].toValue.toReal();
+ if (pc->heightIsSet() && i < actions.size() - 1)
+ h = actions[++i].toValue.toReal();
+ const QPointF &transformOrigin
+ = d->computeTransformOrigin(target->transformOrigin(), w,h);
+ qreal tempxt = transformOrigin.x();
+ qreal tempyt = transformOrigin.y();
+ QTransform t;
+ t.translate(-tempxt, -tempyt);
+ t.rotate(rotation);
+ t.scale(scale, scale);
+ t.translate(tempxt, tempyt);
+ const QPointF &offset = t.map(QPointF(0,0));
+ x += offset.x();
+ y += offset.y();
+ }
+
+ if (ok) {
+ //qDebug() << x << y << rotation << scale;
+ xAction.toValue = x;
+ yAction.toValue = y;
+ sAction.toValue = sAction.toValue.toReal() * scale;
+ rAction.toValue = rAction.toValue.toReal() + rotation;
+ }
+ }
+ }
+ }
+
+ if (data->actions.count()) {
+ if (direction == QDeclarativeAbstractAnimation::Forward) {
+ d->startAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped);
+ d->endAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped);
+ } else {
+ d->endAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped);
+ d->startAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped);
+ }
+ } else {
+ delete data;
+ delete viaData;
+ }
+
+ //take care of any child animations
+ bool valid = d->defaultProperty.isValid();
+ for (int ii = 0; ii < d->animations.count(); ++ii) {
+ if (valid)
+ d->animations.at(ii)->setDefaultTarget(d->defaultProperty);
+ d->animations.at(ii)->transition(actions, modified, direction);
+ }
+
+}
+
+QAbstractAnimation *QSGParentAnimation::qtAnimation()
+{
+ Q_D(QSGParentAnimation);
+ return d->topLevelGroup;
+}
+
+QSGAnchorAnimation::QSGAnchorAnimation(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QSGAnchorAnimationPrivate), parent)
+{
+ Q_D(QSGAnchorAnimation);
+ d->va = new QDeclarativeBulkValueAnimator;
+ QDeclarative_setParent_noEvent(d->va, this);
+}
+
+QSGAnchorAnimation::~QSGAnchorAnimation()
+{
+}
+
+QAbstractAnimation *QSGAnchorAnimation::qtAnimation()
+{
+ Q_D(QSGAnchorAnimation);
+ return d->va;
+}
+
+QDeclarativeListProperty<QSGItem> QSGAnchorAnimation::targets()
+{
+ Q_D(QSGAnchorAnimation);
+ return QDeclarativeListProperty<QSGItem>(this, d->targets);
+}
+
+int QSGAnchorAnimation::duration() const
+{
+ Q_D(const QSGAnchorAnimation);
+ return d->va->duration();
+}
+
+void QSGAnchorAnimation::setDuration(int duration)
+{
+ if (duration < 0) {
+ qmlInfo(this) << tr("Cannot set a duration of < 0");
+ return;
+ }
+
+ Q_D(QSGAnchorAnimation);
+ if (d->va->duration() == duration)
+ return;
+ d->va->setDuration(duration);
+ emit durationChanged(duration);
+}
+
+QEasingCurve QSGAnchorAnimation::easing() const
+{
+ Q_D(const QSGAnchorAnimation);
+ return d->va->easingCurve();
+}
+
+void QSGAnchorAnimation::setEasing(const QEasingCurve &e)
+{
+ Q_D(QSGAnchorAnimation);
+ if (d->va->easingCurve() == e)
+ return;
+
+ d->va->setEasingCurve(e);
+ emit easingChanged(e);
+}
+
+void QSGAnchorAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_UNUSED(modified);
+ Q_D(QSGAnchorAnimation);
+ QDeclarativeAnimationPropertyUpdater *data = new QDeclarativeAnimationPropertyUpdater;
+ data->interpolatorType = QMetaType::QReal;
+ data->interpolator = d->interpolator;
+
+ data->reverse = direction == Backward ? true : false;
+ data->fromSourced = false;
+ data->fromDefined = false;
+
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+ if (action.event && action.event->typeName() == QLatin1String("AnchorChanges")
+ && (d->targets.isEmpty() || d->targets.contains(static_cast<QSGAnchorChanges*>(action.event)->object()))) {
+ data->actions << static_cast<QSGAnchorChanges*>(action.event)->additionalActions();
+ }
+ }
+
+ if (data->actions.count()) {
+ if (!d->rangeIsSet) {
+ d->va->setStartValue(qreal(0));
+ d->va->setEndValue(qreal(1));
+ d->rangeIsSet = true;
+ }
+ d->va->setAnimValue(data, QAbstractAnimation::DeleteWhenStopped);
+ d->va->setFromSourcedValue(&data->fromSourced);
+ } else {
+ delete data;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsganimation_p.h b/src/declarative/items/qsganimation_p.h
new file mode 100644
index 0000000000..7c63331cfe
--- /dev/null
+++ b/src/declarative/items/qsganimation_p.h
@@ -0,0 +1,132 @@
+// Commit: e39a2e39451bf106a9845f8a60fc571faaa4dde5
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANIMATION_H
+#define QSGANIMATION_H
+
+#include "qsgitem.h"
+
+#include <private/qdeclarativeanimation_p.h>
+
+#include <QtCore/qabstractanimation.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGParentAnimationPrivate;
+class QSGParentAnimation : public QDeclarativeAnimationGroup
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGParentAnimation)
+
+ Q_PROPERTY(QSGItem *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(QSGItem *newParent READ newParent WRITE setNewParent NOTIFY newParentChanged)
+ Q_PROPERTY(QSGItem *via READ via WRITE setVia NOTIFY viaChanged)
+
+public:
+ QSGParentAnimation(QObject *parent=0);
+ virtual ~QSGParentAnimation();
+
+ QSGItem *target() const;
+ void setTarget(QSGItem *);
+
+ QSGItem *newParent() const;
+ void setNewParent(QSGItem *);
+
+ QSGItem *via() const;
+ void setVia(QSGItem *);
+
+Q_SIGNALS:
+ void targetChanged();
+ void newParentChanged();
+ void viaChanged();
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QSGAnchorAnimationPrivate;
+class QSGAnchorAnimation : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGAnchorAnimation)
+ Q_PROPERTY(QDeclarativeListProperty<QSGItem> targets READ targets)
+ Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+ Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged)
+
+public:
+ QSGAnchorAnimation(QObject *parent=0);
+ virtual ~QSGAnchorAnimation();
+
+ QDeclarativeListProperty<QSGItem> targets();
+
+ int duration() const;
+ void setDuration(int);
+
+ QEasingCurve easing() const;
+ void setEasing(const QEasingCurve &);
+
+Q_SIGNALS:
+ void durationChanged(int);
+ void easingChanged(const QEasingCurve&);
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGParentAnimation)
+QML_DECLARE_TYPE(QSGAnchorAnimation)
+
+QT_END_HEADER
+
+#endif // QSGANIMATION_H
diff --git a/src/declarative/items/qsganimation_p_p.h b/src/declarative/items/qsganimation_p_p.h
new file mode 100644
index 0000000000..10457d6b52
--- /dev/null
+++ b/src/declarative/items/qsganimation_p_p.h
@@ -0,0 +1,97 @@
+// Commit: 0ade09152067324f74678f2de4d447b6e0280600
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANIMATION_P_H
+#define QSGANIMATION_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 "qsganimation_p.h"
+
+#include <private/qdeclarativeanimation_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGParentAnimationPrivate : public QDeclarativeAnimationGroupPrivate
+{
+ Q_DECLARE_PUBLIC(QSGParentAnimation)
+public:
+ QSGParentAnimationPrivate()
+ : QDeclarativeAnimationGroupPrivate(), target(0), newParent(0),
+ via(0), topLevelGroup(0), startAction(0), endAction(0) {}
+
+ QSGItem *target;
+ QSGItem *newParent;
+ QSGItem *via;
+
+ QSequentialAnimationGroup *topLevelGroup;
+ QActionAnimation *startAction;
+ QActionAnimation *endAction;
+
+ QPointF computeTransformOrigin(QSGItem::TransformOrigin origin, qreal width, qreal height) const;
+};
+
+class QSGAnchorAnimationPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QSGAnchorAnimation)
+public:
+ QSGAnchorAnimationPrivate() : rangeIsSet(false), va(0),
+ interpolator(QVariantAnimationPrivate::getInterpolator(QMetaType::QReal)) {}
+
+ bool rangeIsSet;
+ QDeclarativeBulkValueAnimator *va;
+ QVariantAnimation::Interpolator interpolator;
+ QList<QSGItem*> targets;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGANIMATION_P_H
diff --git a/src/declarative/items/qsgborderimage.cpp b/src/declarative/items/qsgborderimage.cpp
new file mode 100644
index 0000000000..108d87ef28
--- /dev/null
+++ b/src/declarative/items/qsgborderimage.cpp
@@ -0,0 +1,359 @@
+// Commit: 462429f5692f810bdd4e04b916db5f9af428d9e4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgborderimage_p.h"
+#include "qsgborderimage_p_p.h"
+#include "qsgninepatchnode_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qfile.h>
+
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGBorderImage::QSGBorderImage(QSGItem *parent)
+: QSGImageBase(*(new QSGBorderImagePrivate), parent)
+{
+}
+
+QSGBorderImage::~QSGBorderImage()
+{
+ Q_D(QSGBorderImage);
+ if (d->sciReply)
+ d->sciReply->deleteLater();
+}
+
+void QSGBorderImage::setSource(const QUrl &url)
+{
+ Q_D(QSGBorderImage);
+ //equality is fairly expensive, so we bypass for simple, common case
+ if ((d->url.isEmpty() == url.isEmpty()) && url == d->url)
+ return;
+
+ if (d->sciReply) {
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
+ }
+
+ d->url = url;
+ d->sciurl = QUrl();
+ emit sourceChanged(d->url);
+
+ if (isComponentComplete())
+ load();
+}
+
+void QSGBorderImage::load()
+{
+ Q_D(QSGBorderImage);
+ if (d->progress != 0.0) {
+ d->progress = 0.0;
+ emit progressChanged(d->progress);
+ }
+
+ if (d->url.isEmpty()) {
+ d->pix.clear(this);
+ d->status = Null;
+ setImplicitWidth(0);
+ setImplicitHeight(0);
+ emit statusChanged(d->status);
+ update();
+ } else {
+ d->status = Loading;
+ if (d->url.path().endsWith(QLatin1String("sci"))) {
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
+ if (!lf.isEmpty()) {
+ QFile file(lf);
+ file.open(QIODevice::ReadOnly);
+ setGridScaledImage(QSGGridScaledImage(&file));
+ } else
+#endif
+ {
+ QNetworkRequest req(d->url);
+ d->sciReply = qmlEngine(this)->networkAccessManager()->get(req);
+
+ static int sciReplyFinished = -1;
+ static int thisSciRequestFinished = -1;
+ if (sciReplyFinished == -1) {
+ sciReplyFinished =
+ QNetworkReply::staticMetaObject.indexOfSignal("finished()");
+ thisSciRequestFinished =
+ QSGBorderImage::staticMetaObject.indexOfSlot("sciRequestFinished()");
+ }
+
+ QMetaObject::connect(d->sciReply, sciReplyFinished, this,
+ thisSciRequestFinished, Qt::DirectConnection);
+ }
+ } else {
+
+ QDeclarativePixmap::Options options;
+ if (d->async)
+ options |= QDeclarativePixmap::Asynchronous;
+ if (d->cache)
+ options |= QDeclarativePixmap::Cache;
+ d->pix.clear(this);
+ d->pix.load(qmlEngine(this), d->url, options);
+
+ if (d->pix.isLoading()) {
+ d->pix.connectFinished(this, SLOT(requestFinished()));
+ d->pix.connectDownloadProgress(this, SLOT(requestProgress(qint64,qint64)));
+ } else {
+ QSize impsize = d->pix.implicitSize();
+ setImplicitWidth(impsize.width());
+ setImplicitHeight(impsize.height());
+
+ if (d->pix.isReady()) {
+ d->status = Ready;
+ } else {
+ d->status = Error;
+ qmlInfo(this) << d->pix.error();
+ }
+
+ d->progress = 1.0;
+ emit statusChanged(d->status);
+ emit progressChanged(d->progress);
+ update();
+ }
+ }
+ }
+
+ emit statusChanged(d->status);
+}
+
+QSGScaleGrid *QSGBorderImage::border()
+{
+ Q_D(QSGBorderImage);
+ return d->getScaleGrid();
+}
+
+QSGBorderImage::TileMode QSGBorderImage::horizontalTileMode() const
+{
+ Q_D(const QSGBorderImage);
+ return d->horizontalTileMode;
+}
+
+void QSGBorderImage::setHorizontalTileMode(TileMode t)
+{
+ Q_D(QSGBorderImage);
+ if (t != d->horizontalTileMode) {
+ d->horizontalTileMode = t;
+ emit horizontalTileModeChanged();
+ update();
+ }
+}
+
+QSGBorderImage::TileMode QSGBorderImage::verticalTileMode() const
+{
+ Q_D(const QSGBorderImage);
+ return d->verticalTileMode;
+}
+
+void QSGBorderImage::setVerticalTileMode(TileMode t)
+{
+ Q_D(QSGBorderImage);
+ if (t != d->verticalTileMode) {
+ d->verticalTileMode = t;
+ emit verticalTileModeChanged();
+ update();
+ }
+}
+
+void QSGBorderImage::setGridScaledImage(const QSGGridScaledImage& sci)
+{
+ Q_D(QSGBorderImage);
+ if (!sci.isValid()) {
+ d->status = Error;
+ emit statusChanged(d->status);
+ } else {
+ QSGScaleGrid *sg = border();
+ sg->setTop(sci.gridTop());
+ sg->setBottom(sci.gridBottom());
+ sg->setLeft(sci.gridLeft());
+ sg->setRight(sci.gridRight());
+ d->horizontalTileMode = sci.horizontalTileRule();
+ d->verticalTileMode = sci.verticalTileRule();
+
+ d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl()));
+
+ QDeclarativePixmap::Options options;
+ if (d->async)
+ options |= QDeclarativePixmap::Asynchronous;
+ if (d->cache)
+ options |= QDeclarativePixmap::Cache;
+ d->pix.clear(this);
+ d->pix.load(qmlEngine(this), d->sciurl, options);
+
+ if (d->pix.isLoading()) {
+ static int thisRequestProgress = -1;
+ static int thisRequestFinished = -1;
+ if (thisRequestProgress == -1) {
+ thisRequestProgress =
+ QSGBorderImage::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
+ thisRequestFinished =
+ QSGBorderImage::staticMetaObject.indexOfSlot("requestFinished()");
+ }
+
+ d->pix.connectFinished(this, thisRequestFinished);
+ d->pix.connectDownloadProgress(this, thisRequestProgress);
+
+ } else {
+
+ QSize impsize = d->pix.implicitSize();
+ setImplicitWidth(impsize.width());
+ setImplicitHeight(impsize.height());
+
+ if (d->pix.isReady()) {
+ d->status = Ready;
+ } else {
+ d->status = Error;
+ qmlInfo(this) << d->pix.error();
+ }
+
+ d->progress = 1.0;
+ emit statusChanged(d->status);
+ emit progressChanged(1.0);
+ update();
+
+ }
+ }
+}
+
+void QSGBorderImage::requestFinished()
+{
+ Q_D(QSGBorderImage);
+
+ QSize impsize = d->pix.implicitSize();
+ if (d->pix.isError()) {
+ d->status = Error;
+ qmlInfo(this) << d->pix.error();
+ } else {
+ d->status = Ready;
+ }
+
+ setImplicitWidth(impsize.width());
+ setImplicitHeight(impsize.height());
+
+ if (d->sourcesize.width() != d->pix.width() || d->sourcesize.height() != d->pix.height())
+ emit sourceSizeChanged();
+
+ d->progress = 1.0;
+ emit statusChanged(d->status);
+ emit progressChanged(1.0);
+ update();
+}
+
+#define BORDERIMAGE_MAX_REDIRECT 16
+
+void QSGBorderImage::sciRequestFinished()
+{
+ Q_D(QSGBorderImage);
+
+ d->redirectCount++;
+ if (d->redirectCount < BORDERIMAGE_MAX_REDIRECT) {
+ QVariant redirect = d->sciReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = d->sciReply->url().resolved(redirect.toUrl());
+ setSource(url);
+ return;
+ }
+ }
+ d->redirectCount=0;
+
+ if (d->sciReply->error() != QNetworkReply::NoError) {
+ d->status = Error;
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
+ emit statusChanged(d->status);
+ } else {
+ QSGGridScaledImage sci(d->sciReply);
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
+ setGridScaledImage(sci);
+ }
+}
+
+void QSGBorderImage::doUpdate()
+{
+ update();
+}
+
+QSGNode *QSGBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ Q_D(QSGBorderImage);
+
+ if (!d->pix.texture() || width() <= 0 || height() <= 0) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGNinePatchNode *node = static_cast<QSGNinePatchNode *>(oldNode);
+
+ if (!node) {
+ node = new QSGNinePatchNode();
+ }
+
+ node->setTexture(d->pix.texture());
+
+ const QSGScaleGrid *border = d->getScaleGrid();
+ node->setInnerRect(QRectF(border->left(),
+ border->top(),
+ d->pix.width() - border->right() - border->left(),
+ d->pix.height() - border->bottom() - border->top()));
+ node->setRect(QRectF(0, 0, width(), height()));
+ node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+ node->setHorzontalTileMode(d->horizontalTileMode);
+ node->setVerticalTileMode(d->verticalTileMode);
+ node->update();
+
+ return node;
+}
+
+void QSGBorderImage::pixmapChange()
+{
+ Q_D(QSGBorderImage);
+
+ d->pixmapChanged = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgborderimage_p.h b/src/declarative/items/qsgborderimage_p.h
new file mode 100644
index 0000000000..1386264779
--- /dev/null
+++ b/src/declarative/items/qsgborderimage_p.h
@@ -0,0 +1,110 @@
+// Commit: ebd4bc73c46c2962742a682b6a391fb68c482aec
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGBORDERIMAGE_P_H
+#define QSGBORDERIMAGE_P_H
+
+#include "qsgimagebase_p.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGScaleGrid;
+class QSGGridScaledImage;
+class QSGBorderImagePrivate;
+class Q_AUTOTEST_EXPORT QSGBorderImage : public QSGImageBase
+{
+ Q_OBJECT
+ Q_ENUMS(TileMode)
+
+ Q_PROPERTY(QSGScaleGrid *border READ border CONSTANT)
+ Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode NOTIFY horizontalTileModeChanged)
+ Q_PROPERTY(TileMode verticalTileMode READ verticalTileMode WRITE setVerticalTileMode NOTIFY verticalTileModeChanged)
+ // read-only for BorderImage
+ Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged)
+
+public:
+ QSGBorderImage(QSGItem *parent=0);
+ ~QSGBorderImage();
+
+ QSGScaleGrid *border();
+
+ enum TileMode { Stretch = Qt::StretchTile, Repeat = Qt::RepeatTile, Round = Qt::RoundTile };
+
+ TileMode horizontalTileMode() const;
+ void setHorizontalTileMode(TileMode);
+
+ TileMode verticalTileMode() const;
+ void setVerticalTileMode(TileMode);
+
+ void setSource(const QUrl &url);
+
+Q_SIGNALS:
+ void horizontalTileModeChanged();
+ void verticalTileModeChanged();
+ void sourceSizeChanged();
+
+protected:
+ virtual void load();
+ virtual void pixmapChange();
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private:
+ void setGridScaledImage(const QSGGridScaledImage& sci);
+
+private Q_SLOTS:
+ void doUpdate();
+ void requestFinished();
+ void sciRequestFinished();
+
+private:
+ Q_DISABLE_COPY(QSGBorderImage)
+ Q_DECLARE_PRIVATE(QSGBorderImage)
+};
+
+QT_END_NAMESPACE
+QML_DECLARE_TYPE(QSGBorderImage)
+QT_END_HEADER
+
+#endif // QSGBORDERIMAGE_P_H
diff --git a/src/declarative/items/qsgborderimage_p_p.h b/src/declarative/items/qsgborderimage_p_p.h
new file mode 100644
index 0000000000..2fb88d9ffd
--- /dev/null
+++ b/src/declarative/items/qsgborderimage_p_p.h
@@ -0,0 +1,109 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGBORDERIMAGE_P_P_H
+#define QSGBORDERIMAGE_P_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 "qsgimagebase_p_p.h"
+#include "qsgscalegrid_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QSGBorderImagePrivate : public QSGImageBasePrivate
+{
+ Q_DECLARE_PUBLIC(QSGBorderImage)
+
+public:
+ QSGBorderImagePrivate()
+ : border(0), sciReply(0),
+ horizontalTileMode(QSGBorderImage::Stretch),
+ verticalTileMode(QSGBorderImage::Stretch),
+ redirectCount(0), pixmapChanged(false)
+ {
+ }
+
+ ~QSGBorderImagePrivate()
+ {
+ }
+
+
+ QSGScaleGrid *getScaleGrid()
+ {
+ Q_Q(QSGBorderImage);
+ if (!border) {
+ border = new QSGScaleGrid(q);
+ static int borderChangedSignalIdx = -1;
+ static int doUpdateSlotIdx = -1;
+ if (borderChangedSignalIdx < 0)
+ borderChangedSignalIdx = QSGScaleGrid::staticMetaObject.indexOfSignal("borderChanged()");
+ if (doUpdateSlotIdx < 0)
+ doUpdateSlotIdx = QSGBorderImage::staticMetaObject.indexOfSlot("doUpdate()");
+ QMetaObject::connect(border, borderChangedSignalIdx, q, doUpdateSlotIdx);
+ }
+ return border;
+ }
+
+ QSGScaleGrid *border;
+ QUrl sciurl;
+ QNetworkReply *sciReply;
+ QSGBorderImage::TileMode horizontalTileMode;
+ QSGBorderImage::TileMode verticalTileMode;
+ int redirectCount;
+
+ bool pixmapChanged : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGBORDERIMAGE_P_P_H
diff --git a/src/declarative/items/qsgcanvas.cpp b/src/declarative/items/qsgcanvas.cpp
new file mode 100644
index 0000000000..a325f0dac1
--- /dev/null
+++ b/src/declarative/items/qsgcanvas.cpp
@@ -0,0 +1,1890 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgcanvas.h"
+#include "qsgcanvas_p.h"
+
+#include "qsgitem.h"
+#include "qsgitem_p.h"
+
+#include <private/qsgrenderer_p.h>
+#include <private/qsgflashnode_p.h>
+
+#include <QtGui/qpainter.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qinputcontext.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qabstractanimation.h>
+
+#include <private/qdeclarativedebugtrace_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlThreadedRenderer, QML_THREADED_RENDERER)
+
+/*
+Focus behavior
+==============
+
+Prior to being added to a valid canvas items can set and clear focus with no
+effect. Only once items are added to a canvas (by way of having a parent set that
+already belongs to a canvas) do the focus rules apply. Focus goes back to
+having no effect if an item is removed from a canvas.
+
+When an item is moved into a new focus scope (either being added to a canvas
+for the first time, or having its parent changed), if the focus scope already has
+a scope focused item that takes precedence over the item being added. Otherwise,
+the focus of the added tree is used. In the case of of a tree of items being
+added to a canvas for the first time, which may have a conflicted focus state (two
+or more items in one scope having focus set), the same rule is applied item by item -
+thus the first item that has focus will get it (assuming the scope doesn't already
+have a scope focused item), and the other items will have their focus cleared.
+*/
+
+// #define FOCUS_DEBUG
+// #define MOUSE_DEBUG
+// #define TOUCH_DEBUG
+// #define DIRTY_DEBUG
+// #define THREAD_DEBUG
+
+// #define FRAME_TIMING
+
+#ifdef FRAME_TIMING
+static QTime frameTimer;
+int sceneGraphRenderTime;
+int readbackTime;
+#endif
+
+
+class QSGAnimationDriver : public QAnimationDriver
+{
+public:
+ QSGAnimationDriver(QWidget *w, QObject *parent)
+ : QAnimationDriver(parent), widget(w)
+ {
+ Q_ASSERT(w);
+ }
+
+ void started()
+ {
+ widget->update();
+ }
+
+ QWidget *widget;
+};
+
+QSGItem::UpdatePaintNodeData::UpdatePaintNodeData()
+: transformNode(0)
+{
+}
+
+QSGRootItem::QSGRootItem()
+{
+}
+
+QSGThreadedRendererAnimationDriver::QSGThreadedRendererAnimationDriver(QSGCanvasPrivate *r, QObject *parent)
+ : QAnimationDriver(parent)
+ , renderer(r)
+{
+}
+
+void QSGThreadedRendererAnimationDriver::started()
+{
+#ifdef THREAD_DEBUG
+ qWarning("AnimationDriver: Main Thread: started");
+#endif
+ renderer->mutex.lock();
+ renderer->animationRunning = true;
+ if (renderer->idle)
+ renderer->wait.wakeOne();
+ renderer->mutex.unlock();
+
+
+}
+
+void QSGThreadedRendererAnimationDriver::stopped()
+{
+#ifdef THREAD_DEBUG
+ qWarning("AnimationDriver: Main Thread: stopped");
+#endif
+ renderer->mutex.lock();
+ renderer->animationRunning = false;
+ renderer->mutex.unlock();
+}
+
+void QSGCanvas::paintEvent(QPaintEvent *)
+{
+ Q_D(QSGCanvas);
+
+ if (!d->threadedRendering) {
+#ifdef FRAME_TIMING
+ int lastFrame = frameTimer.restart();
+#endif
+
+ if (d->animationDriver->isRunning())
+ d->animationDriver->advance();
+
+#ifdef FRAME_TIMING
+ int animationTime = frameTimer.elapsed();
+#endif
+
+ Q_ASSERT(d->context);
+
+ d->polishItems();
+
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::FramePaint);
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Painting);
+
+#ifdef FRAME_TIMING
+ int polishTime = frameTimer.elapsed();
+#endif
+
+ makeCurrent();
+
+#ifdef FRAME_TIMING
+ int makecurrentTime = frameTimer.elapsed();
+#endif
+
+ d->syncSceneGraph();
+
+#ifdef FRAME_TIMING
+ int syncTime = frameTimer.elapsed();
+#endif
+
+ d->renderSceneGraph();
+
+#ifdef FRAME_TIMING
+ printf("FrameTimes, last=%d, animations=%d, polish=%d, makeCurrent=%d, sync=%d, sgrender=%d, readback=%d, total=%d\n",
+ lastFrame,
+ animationTime,
+ polishTime - animationTime,
+ makecurrentTime - polishTime,
+ syncTime - makecurrentTime,
+ sceneGraphRenderTime - syncTime,
+ readbackTime - sceneGraphRenderTime,
+ frameTimer.elapsed());
+#endif
+
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Painting);
+
+ if (d->animationDriver->isRunning())
+ update();
+ }
+}
+
+void QSGCanvas::resizeEvent(QResizeEvent *e)
+{
+ Q_D(QSGCanvas);
+ if (d->threadedRendering) {
+ d->mutex.lock();
+ QGLWidget::resizeEvent(e);
+ d->widgetSize = e->size();
+ d->mutex.unlock();
+ } else {
+ d->widgetSize = e->size();
+ d->viewportSize = d->widgetSize;
+ QGLWidget::resizeEvent(e);
+ }
+}
+
+void QSGCanvas::showEvent(QShowEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ QGLWidget::showEvent(e);
+
+ if (d->threadedRendering) {
+ d->contextInThread = true;
+ doneCurrent();
+ if (!d->animationDriver)
+ d->animationDriver = new QSGThreadedRendererAnimationDriver(d, this);
+ d->animationDriver->install();
+ d->mutex.lock();
+ d->thread->start();
+ d->wait.wait(&d->mutex);
+ d->mutex.unlock();
+ } else {
+ makeCurrent();
+
+ if (!d->context || !d->context->isReady()) {
+ d->initializeSceneGraph();
+ d->animationDriver = new QSGAnimationDriver(this, this);
+ }
+
+ d->animationDriver->install();
+ }
+}
+
+void QSGCanvas::hideEvent(QHideEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ if (d->threadedRendering) {
+ d->mutex.lock();
+ d->exitThread = true;
+ d->wait.wakeOne();
+ d->wait.wait(&d->mutex);
+ d->exitThread = false;
+ d->mutex.unlock();
+ d->thread->wait();
+ }
+
+ d->animationDriver->uninstall();
+
+ QGLWidget::hideEvent(e);
+}
+
+
+void QSGCanvasPrivate::initializeSceneGraph()
+{
+ if (!context)
+ context = QSGContext::createDefaultContext();
+
+ if (context->isReady())
+ return;
+
+ QGLContext *glctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ context->initialize(glctx);
+
+ if (!threadedRendering) {
+ Q_Q(QSGCanvas);
+ QObject::connect(context->renderer(), SIGNAL(sceneGraphChanged()), q, SLOT(maybeUpdate()),
+ Qt::DirectConnection);
+ }
+
+ if (!QSGItemPrivate::get(rootItem)->itemNode()->parent()) {
+ context->rootNode()->appendChildNode(QSGItemPrivate::get(rootItem)->itemNode());
+ }
+
+ emit q_func()->sceneGraphInitialized();
+}
+
+void QSGCanvasPrivate::polishItems()
+{
+ while (!itemsToPolish.isEmpty()) {
+ QSet<QSGItem *>::Iterator iter = itemsToPolish.begin();
+ QSGItem *item = *iter;
+ itemsToPolish.erase(iter);
+ QSGItemPrivate::get(item)->polishScheduled = false;
+ item->updatePolish();
+ }
+}
+
+
+void QSGCanvasPrivate::syncSceneGraph()
+{
+ updateDirtyNodes();
+}
+
+
+void QSGCanvasPrivate::renderSceneGraph()
+{
+ QGLContext *glctx = const_cast<QGLContext *>(QGLContext::currentContext());
+
+ context->renderer()->setDeviceRect(QRect(QPoint(0, 0), viewportSize));
+ context->renderer()->setViewportRect(QRect(QPoint(0, 0), viewportSize));
+ context->renderer()->setProjectMatrixToDeviceRect();
+
+ context->renderNextFrame();
+
+#ifdef FRAME_TIMING
+ sceneGraphRenderTime = frameTimer.elapsed();
+#endif
+
+
+#ifdef FRAME_TIMING
+ int pixel;
+ glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
+ readbackTime = frameTimer.elapsed();
+#endif
+
+ glctx->swapBuffers();
+}
+
+
+void QSGCanvas::sceneGraphChanged()
+{
+ Q_D(QSGCanvas);
+ d->needsRepaint = true;
+}
+
+
+void QSGCanvasPrivate::runThread()
+{
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render thread running");
+#endif
+ Q_Q(QSGCanvas);
+
+ printf("QSGCanvas::runThread(), rendering in a thread...\n");
+
+ q->makeCurrent();
+ initializeSceneGraph();
+
+ QObject::connect(context->renderer(), SIGNAL(sceneGraphChanged()),
+ q, SLOT(sceneGraphChanged()),
+ Qt::DirectConnection);
+
+ mutex.lock();
+ wait.wakeOne(); // Wake the main thread waiting for us to start
+
+ while (true) {
+ QSize s;
+ s = widgetSize;
+
+ if (exitThread)
+ break;
+
+ if (s != viewportSize) {
+ glViewport(0, 0, s.width(), s.height());
+ viewportSize = s;
+ }
+
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: Waiting for main thread to stop");
+#endif
+ QCoreApplication::postEvent(q, new QEvent(QEvent::User));
+ wait.wait(&mutex);
+
+ if (exitThread) {
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: Shutting down...");
+#endif
+ break;
+ }
+
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: Main thread has stopped, syncing scene");
+#endif
+
+ // Do processing while main thread is frozen
+ syncSceneGraph();
+
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: Resuming main thread");
+#endif
+
+ // Read animationRunning while inside the locked section
+ bool continous = animationRunning;
+
+ wait.wakeOne();
+ mutex.unlock();
+
+ bool enterIdle = false;
+ if (needsRepaint) {
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: rendering scene");
+#endif
+ renderSceneGraph();
+ needsRepaint = false;
+ } else if (continous) {
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: waiting a while...");
+#endif
+ MyThread::doWait();
+ } else {
+ enterIdle = true;
+ }
+
+ mutex.lock();
+
+ if (enterIdle) {
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: Nothing has changed, going idle...");
+#endif
+ idle = true;
+ wait.wait(&mutex);
+ idle = false;
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: waking up from idle");
+#endif
+ }
+
+ }
+
+
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Render Thread: shutting down, waking up main thread");
+#endif
+ wait.wakeOne();
+ mutex.unlock();
+
+ q->doneCurrent();
+}
+
+QSGCanvasPrivate::QSGCanvasPrivate()
+ : rootItem(0)
+ , activeFocusItem(0)
+ , mouseGrabberItem(0)
+ , hoverItem(0)
+ , dirtyItemList(0)
+ , context(0)
+ , contextInThread(false)
+ , threadedRendering(false)
+ , exitThread(false)
+ , animationRunning(false)
+ , idle(false)
+ , needsRepaint(true)
+ , renderThreadAwakened(false)
+ , thread(new MyThread(this))
+ , animationDriver(0)
+{
+ threadedRendering = qmlThreadedRenderer();
+}
+
+QSGCanvasPrivate::~QSGCanvasPrivate()
+{
+}
+
+void QSGCanvasPrivate::init(QSGCanvas *c)
+{
+ q_ptr = c;
+
+ Q_Q(QSGCanvas);
+
+ q->setAttribute(Qt::WA_AcceptTouchEvents);
+ q->setFocusPolicy(Qt::StrongFocus);
+
+ rootItem = new QSGRootItem;
+ QSGItemPrivate *rootItemPrivate = QSGItemPrivate::get(rootItem);
+ rootItemPrivate->canvas = q;
+ rootItemPrivate->flags |= QSGItem::ItemIsFocusScope;
+ rootItemPrivate->focus = true;
+ rootItemPrivate->activeFocus = true;
+ activeFocusItem = rootItem;
+
+ context = QSGContext::createDefaultContext();
+}
+
+void QSGCanvasPrivate::sceneMouseEventForTransform(QGraphicsSceneMouseEvent &sceneEvent,
+ const QTransform &transform)
+{
+ sceneEvent.setPos(transform.map(sceneEvent.scenePos()));
+ sceneEvent.setLastPos(transform.map(sceneEvent.lastScenePos()));
+ for (int ii = 0; ii < 5; ++ii) {
+ if (sceneEvent.buttons() & (1 << ii)) {
+ sceneEvent.setButtonDownPos((Qt::MouseButton)(1 << ii),
+ transform.map(sceneEvent.buttonDownScenePos((Qt::MouseButton)(1 << ii))));
+ }
+ }
+}
+
+void QSGCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
+{
+ for (int i=0; i<touchPoints.count(); i++) {
+ QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
+ touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
+ touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
+ touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
+ }
+}
+
+QEvent::Type QSGCanvasPrivate::sceneMouseEventTypeFromMouseEvent(QMouseEvent *event)
+{
+ switch(event->type()) {
+ default:
+ Q_ASSERT(!"Unknown event type");
+ case QEvent::MouseButtonPress:
+ return QEvent::GraphicsSceneMousePress;
+ case QEvent::MouseButtonRelease:
+ return QEvent::GraphicsSceneMouseRelease;
+ case QEvent::MouseButtonDblClick:
+ return QEvent::GraphicsSceneMouseDoubleClick;
+ case QEvent::MouseMove:
+ return QEvent::GraphicsSceneMouseMove;
+ }
+}
+
+/*!
+Fill in the data in \a sceneEvent based on \a event. This method leaves the item local positions in
+\a sceneEvent untouched. Use sceneMouseEventForTransform() to fill in those details.
+*/
+void QSGCanvasPrivate::sceneMouseEventFromMouseEvent(QGraphicsSceneMouseEvent &sceneEvent, QMouseEvent *event)
+{
+ Q_Q(QSGCanvas);
+
+ Q_ASSERT(event);
+
+ if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) {
+ if ((event->button() & event->buttons()) == event->buttons()) {
+ lastMousePosition = event->pos();
+ }
+
+ switch (event->button()) {
+ default:
+ Q_ASSERT(!"Unknown button");
+ case Qt::LeftButton:
+ buttonDownPositions[0] = event->pos();
+ break;
+ case Qt::RightButton:
+ buttonDownPositions[1] = event->pos();
+ break;
+ case Qt::MiddleButton:
+ buttonDownPositions[2] = event->pos();
+ break;
+ case Qt::XButton1:
+ buttonDownPositions[3] = event->pos();
+ break;
+ case Qt::XButton2:
+ buttonDownPositions[4] = event->pos();
+ break;
+ }
+ }
+
+ sceneEvent.setScenePos(event->pos());
+ sceneEvent.setScreenPos(event->globalPos());
+ sceneEvent.setLastScenePos(lastMousePosition);
+ sceneEvent.setLastScreenPos(q->mapToGlobal(lastMousePosition));
+ sceneEvent.setButtons(event->buttons());
+ sceneEvent.setButton(event->button());
+ sceneEvent.setModifiers(event->modifiers());
+ sceneEvent.setWidget(q);
+
+ for (int ii = 0; ii < 5; ++ii) {
+ if (sceneEvent.buttons() & (1 << ii)) {
+ sceneEvent.setButtonDownScenePos((Qt::MouseButton)(1 << ii), buttonDownPositions[ii]);
+ sceneEvent.setButtonDownScreenPos((Qt::MouseButton)(1 << ii), q->mapToGlobal(buttonDownPositions[ii]));
+ }
+ }
+
+ lastMousePosition = event->pos();
+}
+
+/*!
+Fill in the data in \a hoverEvent based on \a mouseEvent. This method leaves the item local positions in
+\a hoverEvent untouched (these are filled in later).
+*/
+void QSGCanvasPrivate::sceneHoverEventFromMouseEvent(QGraphicsSceneHoverEvent &hoverEvent, QMouseEvent *mouseEvent)
+{
+ Q_Q(QSGCanvas);
+ hoverEvent.setWidget(q);
+ hoverEvent.setScenePos(mouseEvent->pos());
+ hoverEvent.setScreenPos(mouseEvent->globalPos());
+ if (lastMousePosition.isNull()) lastMousePosition = mouseEvent->pos();
+ hoverEvent.setLastScenePos(lastMousePosition);
+ hoverEvent.setLastScreenPos(q->mapToGlobal(lastMousePosition));
+ hoverEvent.setModifiers(mouseEvent->modifiers());
+ hoverEvent.setAccepted(mouseEvent->isAccepted());
+
+ lastMousePosition = mouseEvent->pos();
+}
+
+/*!
+Translates the data in \a touchEvent to this canvas. This method leaves the item local positions in
+\a touchEvent untouched (these are filled in later).
+*/
+void QSGCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
+{
+ Q_Q(QSGCanvas);
+
+ touchEvent->setWidget(q);
+
+ QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
+ for (int i = 0; i < touchPoints.count(); ++i) {
+ QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
+
+ touchPoint.setScreenRect(touchPoint.sceneRect());
+ touchPoint.setStartScreenPos(touchPoint.startScenePos());
+ touchPoint.setLastScreenPos(touchPoint.lastScenePos());
+
+ touchPoint.setSceneRect(touchPoint.rect());
+ touchPoint.setStartScenePos(touchPoint.startPos());
+ touchPoint.setLastScenePos(touchPoint.lastPos());
+
+ if (touchPoint.isPrimary())
+ lastMousePosition = touchPoint.pos().toPoint();
+ }
+ touchEvent->setTouchPoints(touchPoints);
+}
+
+void QSGCanvasPrivate::setFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions options)
+{
+ Q_Q(QSGCanvas);
+
+ Q_ASSERT(item);
+ Q_ASSERT(scope);
+
+#ifdef FOCUS_DEBUG
+ qWarning() << "QSGCanvasPrivate::setFocusInScope():";
+ qWarning() << " scope:" << (QObject *)scope;
+ qWarning() << " scopeSubFocusItem:" << (QObject *)QSGItemPrivate::get(scope)->subFocusItem;
+ qWarning() << " item:" << (QObject *)item;
+ qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
+#endif
+
+ QSGItemPrivate *scopePrivate = QSGItemPrivate::get(scope);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+
+ QSGItem *oldActiveFocusItem = 0;
+ QSGItem *newActiveFocusItem = 0;
+
+ QVarLengthArray<QSGItem *, 20> changed;
+
+ // Does this change the active focus?
+ if (scopePrivate->activeFocus) {
+ oldActiveFocusItem = activeFocusItem;
+ newActiveFocusItem = item;
+ while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
+ newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
+
+ Q_ASSERT(oldActiveFocusItem);
+
+#ifndef QT_NO_IM
+ if (QInputContext *ic = inputContext())
+ ic->reset();
+#endif
+
+ activeFocusItem = 0;
+ QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
+ q->sendEvent(oldActiveFocusItem, &event);
+
+ QSGItem *afi = oldActiveFocusItem;
+ while (afi != scope) {
+ if (QSGItemPrivate::get(afi)->activeFocus) {
+ QSGItemPrivate::get(afi)->activeFocus = false;
+ changed << afi;
+ }
+ afi = afi->parentItem();
+ }
+ }
+
+ QSGItem *oldSubFocusItem = scopePrivate->subFocusItem;
+ // Correct focus chain in scope
+ if (oldSubFocusItem) {
+ QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
+ while (sfi != scope) {
+ QSGItemPrivate::get(sfi)->subFocusItem = 0;
+ sfi = sfi->parentItem();
+ }
+ }
+ {
+ scopePrivate->subFocusItem = item;
+ QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
+ while (sfi != scope) {
+ QSGItemPrivate::get(sfi)->subFocusItem = item;
+ sfi = sfi->parentItem();
+ }
+ }
+
+ if (oldSubFocusItem) {
+ QSGItemPrivate::get(oldSubFocusItem)->focus = false;
+ changed << oldSubFocusItem;
+ }
+
+ if (!(options & DontChangeFocusProperty)) {
+ itemPrivate->focus = true;
+ changed << item;
+ }
+
+ if (newActiveFocusItem) {
+ activeFocusItem = newActiveFocusItem;
+
+ QSGItemPrivate::get(newActiveFocusItem)->activeFocus = true;
+ changed << newActiveFocusItem;
+
+ QSGItem *afi = newActiveFocusItem->parentItem();
+ while (afi != scope) {
+ if (afi->isFocusScope()) {
+ QSGItemPrivate::get(afi)->activeFocus = true;
+ changed << afi;
+ }
+ afi = afi->parentItem();
+ }
+
+ updateInputMethodData();
+
+ QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
+ q->sendEvent(newActiveFocusItem, &event);
+ } else {
+ updateInputMethodData();
+ }
+
+ if (!changed.isEmpty())
+ notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+}
+
+void QSGCanvasPrivate::clearFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions options)
+{
+ Q_Q(QSGCanvas);
+
+ Q_ASSERT(item);
+ Q_ASSERT(scope);
+
+#ifdef FOCUS_DEBUG
+ qWarning() << "QSGCanvasPrivate::clearFocusInScope():";
+ qWarning() << " scope:" << (QObject *)scope;
+ qWarning() << " item:" << (QObject *)item;
+ qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
+#endif
+
+ QSGItemPrivate *scopePrivate = QSGItemPrivate::get(scope);
+
+ QSGItem *oldActiveFocusItem = 0;
+ QSGItem *newActiveFocusItem = 0;
+
+ QVarLengthArray<QSGItem *, 20> changed;
+
+ Q_ASSERT(item == scopePrivate->subFocusItem);
+
+ // Does this change the active focus?
+ if (scopePrivate->activeFocus) {
+ oldActiveFocusItem = activeFocusItem;
+ newActiveFocusItem = scope;
+
+ Q_ASSERT(oldActiveFocusItem);
+
+#ifndef QT_NO_IM
+ if (QInputContext *ic = inputContext())
+ ic->reset();
+#endif
+
+ activeFocusItem = 0;
+ QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
+ q->sendEvent(oldActiveFocusItem, &event);
+
+ QSGItem *afi = oldActiveFocusItem;
+ while (afi != scope) {
+ if (QSGItemPrivate::get(afi)->activeFocus) {
+ QSGItemPrivate::get(afi)->activeFocus = false;
+ changed << afi;
+ }
+ afi = afi->parentItem();
+ }
+ }
+
+ QSGItem *oldSubFocusItem = scopePrivate->subFocusItem;
+ // Correct focus chain in scope
+ if (oldSubFocusItem) {
+ QSGItem *sfi = scopePrivate->subFocusItem->parentItem();
+ while (sfi != scope) {
+ QSGItemPrivate::get(sfi)->subFocusItem = 0;
+ sfi = sfi->parentItem();
+ }
+ }
+ scopePrivate->subFocusItem = 0;
+
+ if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
+ QSGItemPrivate::get(oldSubFocusItem)->focus = false;
+ changed << oldSubFocusItem;
+ }
+
+ if (newActiveFocusItem) {
+ Q_ASSERT(newActiveFocusItem == scope);
+ activeFocusItem = scope;
+
+ updateInputMethodData();
+
+ QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
+ q->sendEvent(newActiveFocusItem, &event);
+ } else {
+ updateInputMethodData();
+ }
+
+ if (!changed.isEmpty())
+ notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+}
+
+void QSGCanvasPrivate::notifyFocusChangesRecur(QSGItem **items, int remaining)
+{
+ QDeclarativeGuard<QSGItem> item(*items);
+
+ if (remaining)
+ notifyFocusChangesRecur(items + 1, remaining - 1);
+
+ if (item) {
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+
+ if (itemPrivate->notifiedFocus != itemPrivate->focus) {
+ itemPrivate->notifiedFocus = itemPrivate->focus;
+ emit item->focusChanged(itemPrivate->focus);
+ }
+
+ if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
+ itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
+ itemPrivate->itemChange(QSGItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
+ emit item->activeFocusChanged(itemPrivate->activeFocus);
+ }
+ }
+}
+
+void QSGCanvasPrivate::updateInputMethodData()
+{
+ Q_Q(QSGCanvas);
+ bool enabled = activeFocusItem
+ && (QSGItemPrivate::get(activeFocusItem)->flags & QSGItem::ItemAcceptsInputMethod);
+ q->setAttribute(Qt::WA_InputMethodEnabled, enabled);
+ q->setInputMethodHints(enabled ? activeFocusItem->inputMethodHints() : Qt::ImhNone);
+}
+
+QVariant QSGCanvas::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QSGCanvas);
+ if (!d->activeFocusItem || !(QSGItemPrivate::get(d->activeFocusItem)->flags & QSGItem::ItemAcceptsInputMethod))
+ return QVariant();
+ QVariant value = d->activeFocusItem->inputMethodQuery(query);
+
+ //map geometry types
+ QVariant::Type type = value.type();
+ if (type == QVariant::RectF || type == QVariant::Rect) {
+ const QTransform transform = QSGItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
+ value = transform.mapRect(value.toRectF());
+ } else if (type == QVariant::PointF || type == QVariant::Point) {
+ const QTransform transform = QSGItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
+ value = transform.map(value.toPointF());
+ }
+ return value;
+}
+
+void QSGCanvasPrivate::dirtyItem(QSGItem *)
+{
+ Q_Q(QSGCanvas);
+ q->maybeUpdate();
+}
+
+void QSGCanvasPrivate::cleanup(QSGNode *n)
+{
+ Q_Q(QSGCanvas);
+
+ Q_ASSERT(!cleanupNodeList.contains(n));
+ cleanupNodeList.append(n);
+ q->maybeUpdate();
+}
+
+static QGLFormat tweakFormat(const QGLFormat &format = QGLFormat::defaultFormat())
+{
+ QGLFormat f = format;
+ f.setSwapInterval(1);
+ return f;
+}
+
+QSGCanvas::QSGCanvas(QWidget *parent, Qt::WindowFlags f)
+ : QGLWidget(*(new QSGCanvasPrivate), tweakFormat(), parent, (QGLWidget *) 0, f)
+{
+ Q_D(QSGCanvas);
+
+ d->init(this);
+}
+
+QSGCanvas::QSGCanvas(const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
+ : QGLWidget(*(new QSGCanvasPrivate), tweakFormat(format), parent, (QGLWidget *) 0, f)
+{
+ Q_D(QSGCanvas);
+
+ d->init(this);
+}
+
+QSGCanvas::QSGCanvas(QSGCanvasPrivate &dd, QWidget *parent, Qt::WindowFlags f)
+: QGLWidget(dd, tweakFormat(), parent, 0, f)
+{
+ Q_D(QSGCanvas);
+
+ d->init(this);
+}
+
+QSGCanvas::QSGCanvas(QSGCanvasPrivate &dd, const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
+: QGLWidget(dd, tweakFormat(format), parent, 0, f)
+{
+ Q_D(QSGCanvas);
+
+ d->init(this);
+}
+
+QSGCanvas::~QSGCanvas()
+{
+ Q_D(QSGCanvas);
+
+ // ### should we change ~QSGItem to handle this better?
+ // manually cleanup for the root item (item destructor only handles these when an item is parented)
+ QSGItemPrivate *rootItemPrivate = QSGItemPrivate::get(d->rootItem);
+ rootItemPrivate->removeFromDirtyList();
+ rootItemPrivate->canvas = 0;
+
+ delete d->rootItem; d->rootItem = 0;
+ d->cleanupNodes();
+
+ delete d->context;
+}
+
+QSGItem *QSGCanvas::rootItem() const
+{
+ Q_D(const QSGCanvas);
+
+ return d->rootItem;
+}
+
+QSGItem *QSGCanvas::activeFocusItem() const
+{
+ Q_D(const QSGCanvas);
+
+ return d->activeFocusItem;
+}
+
+QSGItem *QSGCanvas::mouseGrabberItem() const
+{
+ Q_D(const QSGCanvas);
+
+ return d->mouseGrabberItem;
+}
+
+
+void QSGCanvasPrivate::clearHover()
+{
+ Q_Q(QSGCanvas);
+ if (!hoverItem)
+ return;
+
+ QGraphicsSceneHoverEvent hoverEvent;
+ hoverEvent.setWidget(q);
+
+ QPoint cursorPos = QCursor::pos();
+ hoverEvent.setScenePos(q->mapFromGlobal(cursorPos));
+ hoverEvent.setLastScenePos(hoverEvent.scenePos());
+ hoverEvent.setScreenPos(cursorPos);
+ hoverEvent.setLastScreenPos(hoverEvent.screenPos());
+
+ QSGItem *item = hoverItem;
+ hoverItem = 0;
+ sendHoverEvent(QEvent::GraphicsSceneHoverLeave, item, &hoverEvent);
+}
+
+
+bool QSGCanvas::event(QEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ if (e->type() == QEvent::User) {
+ Q_ASSERT(d->threadedRendering);
+
+ d->mutex.lock();
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Main Thread: Stopped");
+#endif
+
+ d->polishItems();
+
+ d->renderThreadAwakened = false;
+
+ d->wait.wakeOne();
+
+ // The thread is exited when the widget has been hidden. We then need to
+ // skip the waiting, otherwise we would be waiting for a wakeup that never
+ // comes.
+ if (d->thread->isRunning())
+ d->wait.wait(&d->mutex);
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: Main Thread: Resumed");
+#endif
+ d->mutex.unlock();
+
+ if (d->animationRunning)
+ d->animationDriver->advance();
+ }
+
+ switch (e->type()) {
+
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ {
+ QTouchEvent *touch = static_cast<QTouchEvent *>(e);
+ d->translateTouchEvent(touch);
+ d->deliverTouchEvent(touch);
+ if (!touch->isAccepted())
+ return false;
+ }
+ case QEvent::Leave:
+ d->clearHover();
+ d->lastMousePosition = QPoint();
+ break;
+ default:
+ break;
+ }
+
+ return QGLWidget::event(e);
+}
+
+void QSGCanvas::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ sendEvent(d->activeFocusItem, e);
+}
+
+void QSGCanvas::keyReleaseEvent(QKeyEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ sendEvent(d->activeFocusItem, e);
+}
+
+void QSGCanvas::inputMethodEvent(QInputMethodEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ sendEvent(d->activeFocusItem, e);
+}
+
+bool QSGCanvasPrivate::deliverInitialMousePressEvent(QSGItem *item, QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGCanvas);
+
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ return false;
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isVisible() || !child->isEnabled())
+ continue;
+ if (deliverInitialMousePressEvent(child, event))
+ return true;
+ }
+
+ if (itemPrivate->acceptedMouseButtons & event->button()) {
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ sceneMouseEventForTransform(*event, itemPrivate->canvasToItemTransform());
+ event->accept();
+ mouseGrabberItem = item;
+ q->sendEvent(item, event);
+ if (event->isAccepted())
+ return true;
+ mouseGrabberItem->ungrabMouse();
+ mouseGrabberItem = 0;
+ }
+ }
+
+ return false;
+}
+
+bool QSGCanvasPrivate::deliverMouseEvent(QGraphicsSceneMouseEvent *sceneEvent)
+{
+ Q_Q(QSGCanvas);
+
+ if (!mouseGrabberItem &&
+ sceneEvent->type() == QEvent::GraphicsSceneMousePress &&
+ (sceneEvent->button() & sceneEvent->buttons()) == sceneEvent->buttons()) {
+
+ return deliverInitialMousePressEvent(rootItem, sceneEvent);
+ }
+
+ if (mouseGrabberItem) {
+ QSGItemPrivate *mgPrivate = QSGItemPrivate::get(mouseGrabberItem);
+ sceneMouseEventForTransform(*sceneEvent, mgPrivate->canvasToItemTransform());
+
+ sceneEvent->accept();
+ q->sendEvent(mouseGrabberItem, sceneEvent);
+ if (sceneEvent->isAccepted())
+ return true;
+ }
+
+ return false;
+}
+
+void QSGCanvas::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QSGCanvas);
+
+#ifdef MOUSE_DEBUG
+ qWarning() << "QSGCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
+#endif
+
+ QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
+ d->sceneMouseEventFromMouseEvent(sceneEvent, event);
+
+ d->deliverMouseEvent(&sceneEvent);
+ event->setAccepted(sceneEvent.isAccepted());
+}
+
+void QSGCanvas::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QSGCanvas);
+
+#ifdef MOUSE_DEBUG
+ qWarning() << "QSGCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
+#endif
+
+ if (!d->mouseGrabberItem) {
+ QGLWidget::mouseReleaseEvent(event);
+ return;
+ }
+
+ QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
+ d->sceneMouseEventFromMouseEvent(sceneEvent, event);
+
+ d->deliverMouseEvent(&sceneEvent);
+ event->setAccepted(sceneEvent.isAccepted());
+
+ d->mouseGrabberItem = 0;
+}
+
+void QSGCanvas::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_D(QSGCanvas);
+
+#ifdef MOUSE_DEBUG
+ qWarning() << "QSGCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
+#endif
+
+ QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
+ d->sceneMouseEventFromMouseEvent(sceneEvent, event);
+
+ if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
+ if (d->deliverInitialMousePressEvent(d->rootItem, &sceneEvent))
+ event->accept();
+ else
+ event->ignore();
+ return;
+ }
+
+ d->deliverMouseEvent(&sceneEvent);
+ event->setAccepted(sceneEvent.isAccepted());
+}
+
+void QSGCanvasPrivate::sendHoverEvent(QEvent::Type type, QSGItem *item,
+ QGraphicsSceneHoverEvent *event)
+{
+ Q_Q(QSGCanvas);
+ const QTransform transform = QSGItemPrivate::get(item)->canvasToItemTransform();
+
+ //create copy of event
+ QGraphicsSceneHoverEvent hoverEvent(type);
+ hoverEvent.setWidget(event->widget());
+ hoverEvent.setPos(transform.map(event->scenePos()));
+ hoverEvent.setScenePos(event->scenePos());
+ hoverEvent.setScreenPos(event->screenPos());
+ hoverEvent.setLastPos(transform.map(event->lastScenePos()));
+ hoverEvent.setLastScenePos(event->lastScenePos());
+ hoverEvent.setLastScreenPos(event->lastScreenPos());
+ hoverEvent.setModifiers(event->modifiers());
+ hoverEvent.setAccepted(event->isAccepted());
+
+ q->sendEvent(item, &hoverEvent);
+}
+
+void QSGCanvas::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QSGCanvas);
+
+#ifdef MOUSE_DEBUG
+ qWarning() << "QSGCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
+#endif
+
+ if (!d->mouseGrabberItem) {
+ QGraphicsSceneHoverEvent hoverEvent;
+ d->sceneHoverEventFromMouseEvent(hoverEvent, event);
+
+ bool delivered = d->deliverHoverEvent(d->rootItem, &hoverEvent);
+ if (!delivered) {
+ //take care of any exits
+ if (d->hoverItem) {
+ QSGItem *item = d->hoverItem;
+ d->hoverItem = 0;
+ d->sendHoverEvent(QEvent::GraphicsSceneHoverLeave, item, &hoverEvent);
+ }
+ }
+ event->setAccepted(hoverEvent.isAccepted());
+ return;
+ }
+
+ QGraphicsSceneMouseEvent sceneEvent(d->sceneMouseEventTypeFromMouseEvent(event));
+ d->sceneMouseEventFromMouseEvent(sceneEvent, event);
+
+ d->deliverMouseEvent(&sceneEvent);
+ event->setAccepted(sceneEvent.isAccepted());
+}
+
+bool QSGCanvasPrivate::deliverHoverEvent(QSGItem *item, QGraphicsSceneHoverEvent *event)
+{
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ return false;
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isEnabled())
+ continue;
+ if (deliverHoverEvent(child, event))
+ return true;
+ }
+
+ if (itemPrivate->hoverEnabled) {
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ if (hoverItem == item) {
+ //move
+ sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, event);
+ } else {
+ //exit from previous
+ if (hoverItem) {
+ QSGItem *item = hoverItem;
+ hoverItem = 0;
+ sendHoverEvent(QEvent::GraphicsSceneHoverLeave, item, event);
+ }
+
+ //enter new item
+ hoverItem = item;
+ sendHoverEvent(QEvent::GraphicsSceneHoverEnter, item, event);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QSGCanvasPrivate::deliverWheelEvent(QSGItem *item, QGraphicsSceneWheelEvent *event)
+{
+ Q_Q(QSGCanvas);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ return false;
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isEnabled())
+ continue;
+ if (deliverWheelEvent(child, event))
+ return true;
+ }
+
+ QPointF p = item->mapFromScene(event->scenePos());
+ if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ event->setPos(itemPrivate->canvasToItemTransform().map(event->scenePos()));
+ event->accept();
+ q->sendEvent(item, event);
+ if (event->isAccepted())
+ return true;
+ }
+
+ return false;
+}
+
+#ifndef QT_NO_WHEELEVENT
+void QSGCanvas::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QSGCanvas);
+#ifdef MOUSE_DEBUG
+ qWarning() << "QSGCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
+#endif
+ QGraphicsSceneWheelEvent wheelEvent(QEvent::GraphicsSceneWheel);
+ wheelEvent.setWidget(this);
+ wheelEvent.setScenePos(event->pos());
+ wheelEvent.setScreenPos(event->globalPos());
+ wheelEvent.setButtons(event->buttons());
+ wheelEvent.setModifiers(event->modifiers());
+ wheelEvent.setDelta(event->delta());
+ wheelEvent.setOrientation(event->orientation());
+ wheelEvent.setAccepted(false);
+
+ d->deliverWheelEvent(d->rootItem, &wheelEvent);
+ event->setAccepted(wheelEvent.isAccepted());
+}
+#endif // QT_NO_WHEELEVENT
+
+bool QSGCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
+{
+#ifdef TOUCH_DEBUG
+ if (event->type() == QEvent::TouchBegin)
+ qWarning("touchBeginEvent");
+ else if (event->type() == QEvent::TouchUpdate)
+ qWarning("touchUpdateEvent");
+ else if (event->type() == QEvent::TouchEnd)
+ qWarning("touchEndEvent");
+#endif
+
+ QHash<QSGItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
+
+ if (event->type() == QTouchEvent::TouchBegin) { // all points are new touch points
+ QSet<int> acceptedNewPoints;
+ deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
+ if (acceptedNewPoints.count() > 0)
+ event->accept();
+ return event->isAccepted();
+ }
+
+ const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
+ QList<QTouchEvent::TouchPoint> newPoints;
+ QSGItem *item = 0;
+ for (int i=0; i<touchPoints.count(); i++) {
+ const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
+ switch (touchPoint.state()) {
+ case Qt::TouchPointPressed:
+ newPoints << touchPoint;
+ break;
+ case Qt::TouchPointMoved:
+ case Qt::TouchPointStationary:
+ case Qt::TouchPointReleased:
+ if (itemForTouchPointId.contains(touchPoint.id())) {
+ item = itemForTouchPointId[touchPoint.id()];
+ if (item)
+ updatedPoints[item].append(touchPoint);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (newPoints.count() > 0 || updatedPoints.count() > 0) {
+ QSet<int> acceptedNewPoints;
+ int prevCount = updatedPoints.count();
+ deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
+ if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
+ event->accept();
+ }
+
+ if (event->touchPointStates() & Qt::TouchPointReleased) {
+ for (int i=0; i<touchPoints.count(); i++) {
+ if (touchPoints[i].state() == Qt::TouchPointReleased)
+ itemForTouchPointId.remove(touchPoints[i].id());
+ }
+ }
+
+ return event->isAccepted();
+}
+
+bool QSGCanvasPrivate::deliverTouchPoints(QSGItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QSGItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
+{
+ Q_Q(QSGCanvas);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QRectF bounds(0, 0, item->width(), item->height());
+ for (int i=0; i<newPoints.count(); i++) {
+ QPointF p = item->mapFromScene(newPoints[i].scenePos());
+ if (!bounds.contains(p))
+ return false;
+ }
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isEnabled())
+ continue;
+ if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
+ return true;
+ }
+
+ QList<QTouchEvent::TouchPoint> matchingPoints;
+ if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
+ QRectF bounds(0, 0, item->width(), item->height());
+ for (int i=0; i<newPoints.count(); i++) {
+ if (acceptedNewPoints->contains(newPoints[i].id()))
+ continue;
+ QPointF p = item->mapFromScene(newPoints[i].scenePos());
+ if (bounds.contains(p))
+ matchingPoints << newPoints[i];
+ }
+ }
+
+ if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
+ QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
+ eventPoints.append(matchingPoints);
+ transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
+
+ Qt::TouchPointStates eventStates;
+ for (int i=0; i<eventPoints.count(); i++)
+ eventStates |= eventPoints[i].state();
+ // if all points have the same state, set the event type accordingly
+ QEvent::Type eventType;
+ switch (eventStates) {
+ case Qt::TouchPointPressed:
+ eventType = QEvent::TouchBegin;
+ break;
+ case Qt::TouchPointReleased:
+ eventType = QEvent::TouchEnd;
+ break;
+ default:
+ eventType = QEvent::TouchUpdate;
+ break;
+ }
+
+ if (eventStates != Qt::TouchPointStationary) {
+ QTouchEvent touchEvent(eventType);
+ touchEvent.setWidget(q);
+ touchEvent.setDeviceType(event->deviceType());
+ touchEvent.setModifiers(event->modifiers());
+ touchEvent.setTouchPointStates(eventStates);
+ touchEvent.setTouchPoints(eventPoints);
+
+ touchEvent.accept();
+ q->sendEvent(item, &touchEvent);
+
+ if (touchEvent.isAccepted()) {
+ for (int i=0; i<matchingPoints.count(); i++) {
+ itemForTouchPointId[matchingPoints[i].id()] = item;
+ acceptedNewPoints->insert(matchingPoints[i].id());
+ }
+ }
+ }
+ }
+
+ updatedPoints->remove(item);
+ if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
+ return true;
+
+ return false;
+}
+
+bool QSGCanvasPrivate::sendFilteredMouseEvent(QSGItem *target, QSGItem *item, QGraphicsSceneMouseEvent *event)
+{
+ if (!target)
+ return false;
+
+ if (sendFilteredMouseEvent(target->parentItem(), item, event))
+ return true;
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(target);
+ if (targetPrivate->filtersChildMouseEvents)
+ if (target->childMouseEventFilter(item, event))
+ return true;
+
+ return false;
+}
+
+bool QSGCanvas::sendEvent(QSGItem *item, QEvent *e)
+{
+ Q_D(QSGCanvas);
+
+ if (!item) {
+ qWarning("QSGCanvas::sendEvent: Cannot send event to a null item");
+ return false;
+ }
+
+ Q_ASSERT(e);
+
+ switch (e->type()) {
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ QSGItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
+ while (!e->isAccepted() && (item = item->parentItem())) {
+ e->accept();
+ QSGItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
+ }
+ break;
+ case QEvent::InputMethod:
+ QSGItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
+ while (!e->isAccepted() && (item = item->parentItem())) {
+ e->accept();
+ QSGItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
+ }
+ break;
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ QSGItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ case QEvent::GraphicsSceneMouseMove:
+ // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
+ {
+ QGraphicsSceneMouseEvent *se = static_cast<QGraphicsSceneMouseEvent *>(e);
+ if (!d->sendFilteredMouseEvent(item->parentItem(), item, se)) {
+ se->accept();
+ QSGItemPrivate::get(item)->deliverMouseEvent(se);
+ }
+ }
+ break;
+ case QEvent::GraphicsSceneWheel:
+ QSGItemPrivate::get(item)->deliverWheelEvent(static_cast<QGraphicsSceneWheelEvent *>(e));
+ break;
+ case QEvent::GraphicsSceneHoverEnter:
+ case QEvent::GraphicsSceneHoverLeave:
+ case QEvent::GraphicsSceneHoverMove:
+ QSGItemPrivate::get(item)->deliverHoverEvent(static_cast<QGraphicsSceneHoverEvent *>(e));
+ break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ QSGItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void QSGCanvasPrivate::cleanupNodes()
+{
+ for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
+ delete cleanupNodeList.at(ii);
+ cleanupNodeList.clear();
+}
+
+void QSGCanvasPrivate::updateDirtyNodes()
+{
+#ifdef DIRTY_DEBUG
+ qWarning() << "QSGCanvasPrivate::updateDirtyNodes():";
+#endif
+
+ cleanupNodes();
+
+ QSGItem *updateList = dirtyItemList;
+ dirtyItemList = 0;
+ if (updateList) QSGItemPrivate::get(updateList)->prevDirtyItem = &updateList;
+
+ while (updateList) {
+ QSGItem *item = updateList;
+ QSGItemPrivate *itemPriv = QSGItemPrivate::get(item);
+ itemPriv->removeFromDirtyList();
+
+#ifdef DIRTY_DEBUG
+ qWarning() << " QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
+#endif
+ updateDirtyNode(item);
+ }
+}
+
+void QSGCanvasPrivate::updateDirtyNode(QSGItem *item)
+{
+#ifdef QML_RUNTIME_TESTING
+ bool didFlash = false;
+#endif
+
+ QSGItemPrivate *itemPriv = QSGItemPrivate::get(item);
+ quint32 dirty = itemPriv->dirtyAttributes;
+ itemPriv->dirtyAttributes = 0;
+
+ if ((dirty & QSGItemPrivate::TransformUpdateMask) ||
+ (dirty & QSGItemPrivate::Size && itemPriv->origin != QSGItem::TopLeft &&
+ (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
+
+ QMatrix4x4 matrix;
+
+ if (itemPriv->x != 0. || itemPriv->y != 0.)
+ matrix.translate(itemPriv->x, itemPriv->y);
+
+ if (dirty & QSGItemPrivate::ComplexTransformUpdateMask) {
+ for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
+ itemPriv->transforms.at(ii)->applyTo(&matrix);
+ }
+
+ if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
+ QPointF origin = itemPriv->computeTransformOrigin();
+ matrix.translate(origin.x(), origin.y());
+ if (itemPriv->scale != 1.)
+ matrix.scale(itemPriv->scale, itemPriv->scale);
+ if (itemPriv->rotation != 0.)
+ matrix.rotate(itemPriv->rotation, 0, 0, 1);
+ matrix.translate(-origin.x(), -origin.y());
+ }
+
+ itemPriv->itemNode()->setMatrix(matrix);
+ }
+
+ bool clipEffectivelyChanged = dirty & QSGItemPrivate::Clip &&
+ ((item->clip() == false) != (itemPriv->clipNode == 0));
+ bool effectRefEffectivelyChanged = dirty & QSGItemPrivate::EffectReference &&
+ ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
+
+ if (clipEffectivelyChanged) {
+ QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
+ QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
+
+ if (item->clip()) {
+ Q_ASSERT(itemPriv->clipNode == 0);
+ itemPriv->clipNode = new QSGDefaultClipNode(QRectF(0, 0, itemPriv->width, itemPriv->height));
+
+ if (child)
+ parent->removeChildNode(child);
+ parent->appendChildNode(itemPriv->clipNode);
+ if (child)
+ itemPriv->clipNode->appendChildNode(child);
+
+ } else {
+ Q_ASSERT(itemPriv->clipNode != 0);
+ parent->removeChildNode(itemPriv->clipNode);
+ if (child)
+ itemPriv->clipNode->removeChildNode(child);
+ delete itemPriv->clipNode;
+ itemPriv->clipNode = 0;
+ if (child)
+ parent->appendChildNode(child);
+ }
+ }
+
+ if (dirty & QSGItemPrivate::ChildrenUpdateMask) {
+ while (itemPriv->childContainerNode()->childCount())
+ itemPriv->childContainerNode()->removeChildNode(itemPriv->childContainerNode()->childAtIndex(0));
+ }
+
+ if (effectRefEffectivelyChanged) {
+ QSGNode *parent = itemPriv->clipNode;
+ if (!parent)
+ parent = itemPriv->opacityNode;
+ if (!parent)
+ parent = itemPriv->itemNode();
+ QSGNode *child = itemPriv->groupNode;
+
+ if (itemPriv->effectRefCount) {
+ Q_ASSERT(itemPriv->rootNode == 0);
+ itemPriv->rootNode = new QSGRootNode;
+
+ if (child)
+ parent->removeChildNode(child);
+ parent->appendChildNode(itemPriv->rootNode);
+ if (child)
+ itemPriv->rootNode->appendChildNode(child);
+ } else {
+ Q_ASSERT(itemPriv->rootNode != 0);
+ parent->removeChildNode(itemPriv->rootNode);
+ if (child)
+ itemPriv->rootNode->removeChildNode(child);
+ delete itemPriv->rootNode;
+ itemPriv->rootNode = 0;
+ if (child)
+ parent->appendChildNode(child);
+ }
+ }
+
+ if (dirty & QSGItemPrivate::ChildrenUpdateMask) {
+ QSGNode *groupNode = itemPriv->groupNode;
+ if (groupNode) {
+ for (int count = groupNode->childCount(); count; --count)
+ groupNode->removeChildNode(groupNode->childAtIndex(0));
+ }
+
+ QList<QSGItem *> orderedChildren = itemPriv->paintOrderChildItems();
+ int ii = 0;
+
+ itemPriv->paintNodeIndex = 0;
+ for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
+ QSGItemPrivate *childPrivate = QSGItemPrivate::get(orderedChildren.at(ii));
+ if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
+ continue;
+ if (childPrivate->itemNode()->parent())
+ childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
+
+ itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
+ itemPriv->paintNodeIndex++;
+ }
+
+ if (itemPriv->paintNode)
+ itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
+
+ for (; ii < orderedChildren.count(); ++ii) {
+ QSGItemPrivate *childPrivate = QSGItemPrivate::get(orderedChildren.at(ii));
+ if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
+ continue;
+ if (childPrivate->itemNode()->parent())
+ childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
+
+ itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
+ }
+ }
+
+ if ((dirty & QSGItemPrivate::Size || clipEffectivelyChanged) && itemPriv->clipNode) {
+ itemPriv->clipNode->setRect(QRectF(0, 0, itemPriv->width, itemPriv->height));
+ itemPriv->clipNode->update();
+ }
+
+ if (dirty & (QSGItemPrivate::OpacityValue | QSGItemPrivate::Visible | QSGItemPrivate::HideReference)) {
+ qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
+ ? itemPriv->opacity : qreal(0);
+
+ if (opacity != 1 && !itemPriv->opacityNode) {
+ itemPriv->opacityNode = new QSGOpacityNode;
+
+ QSGNode *parent = itemPriv->itemNode();
+ QSGNode *child = itemPriv->clipNode;
+ if (!child)
+ child = itemPriv->rootNode;
+ if (!child)
+ child = itemPriv->groupNode;
+
+ if (child)
+ parent->removeChildNode(child);
+ parent->appendChildNode(itemPriv->opacityNode);
+ if (child)
+ itemPriv->opacityNode->appendChildNode(child);
+ }
+ if (itemPriv->opacityNode)
+ itemPriv->opacityNode->setOpacity(opacity);
+ }
+
+ if (dirty & QSGItemPrivate::ContentUpdateMask) {
+
+ if (itemPriv->flags & QSGItem::ItemHasContents) {
+ updatePaintNodeData.transformNode = itemPriv->itemNode();
+ itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
+
+ Q_ASSERT(itemPriv->paintNode == 0 ||
+ itemPriv->paintNode->parent() == 0 ||
+ itemPriv->paintNode->parent() == itemPriv->childContainerNode());
+
+ if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
+ if (itemPriv->childContainerNode()->childCount() == itemPriv->paintNodeIndex)
+ itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
+ else
+ itemPriv->childContainerNode()->insertChildNodeBefore(itemPriv->paintNode, itemPriv->childContainerNode()->childAtIndex(itemPriv->paintNodeIndex));
+ }
+ } else if (itemPriv->paintNode) {
+ delete itemPriv->paintNode;
+ }
+ }
+
+#ifndef QT_NO_DEBUG
+ // Check consistency.
+ const QSGNode *nodeChain[] = {
+ itemPriv->itemNodeInstance,
+ itemPriv->opacityNode,
+ itemPriv->clipNode,
+ itemPriv->rootNode,
+ itemPriv->groupNode,
+ itemPriv->paintNode,
+ };
+
+ int ip = 0;
+ for (;;) {
+ while (ip < 5 && nodeChain[ip] == 0)
+ ++ip;
+ if (ip == 5)
+ break;
+ int ic = ip + 1;
+ while (ic < 5 && nodeChain[ic] == 0)
+ ++ic;
+ const QSGNode *parent = nodeChain[ip];
+ const QSGNode *child = nodeChain[ic];
+ if (child == 0) {
+ Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
+ } else {
+ Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
+ Q_ASSERT(child->parent() == parent);
+ bool containsChild = false;
+ for (int i = 0; i < parent->childCount(); ++i)
+ containsChild |= (parent->childAtIndex(i) == child);
+ Q_ASSERT(containsChild);
+ }
+ ip = ic;
+ }
+#endif
+
+#ifdef QML_RUNTIME_TESTING
+ if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
+ QSGFlashNode *flash = new QSGFlashNode();
+ flash->setRect(item->boundingRect());
+ itemPriv->childContainerNode()->appendChildNode(flash);
+ didFlash = true;
+ }
+ Q_Q(QSGCanvas);
+ if (didFlash) {
+ q->maybeUpdate();
+ }
+#endif
+
+}
+
+void QSGCanvas::maybeUpdate()
+{
+ Q_D(QSGCanvas);
+
+ if (d->threadedRendering) {
+ if (!d->renderThreadAwakened) {
+ d->renderThreadAwakened = true;
+ bool locked = d->mutex.tryLock();
+ if (d->idle && locked) {
+#ifdef THREAD_DEBUG
+ qWarning("QSGRenderer: now maybe I should update...");
+#endif
+ d->wait.wakeOne();
+ }
+ if (locked)
+ d->mutex.unlock();
+ }
+ } else if (!d->animationDriver || !d->animationDriver->isRunning()) {
+ update();
+ }
+}
+
+/*!
+ \fn void QSGEngine::sceneGraphInitialized();
+
+ This signal is emitted when the scene graph has been initialized.
+
+ This signal will be emitted from the scene graph rendering thread.
+ */
+
+/*!
+ Returns the QSGEngine used for this scene.
+
+ The engine will only be available once the scene graph has been
+ initialized. Register for the sceneGraphEngine() signal to get
+ notification about this.
+ */
+
+QSGEngine *QSGCanvas::sceneGraphEngine() const
+{
+ Q_D(const QSGCanvas);
+ if (d->context->isReady())
+ return d->context->engine();
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgcanvas.h b/src/declarative/items/qsgcanvas.h
new file mode 100644
index 0000000000..8f3b3038f8
--- /dev/null
+++ b/src/declarative/items/qsgcanvas.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCANVAS_H
+#define QSGCANVAS_H
+
+#include <QtCore/qmetatype.h>
+#include <QtOpenGL/qgl.h>
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class QSGEngine;
+class QSGCanvasPrivate;
+class Q_DECLARATIVE_EXPORT QSGCanvas : public QGLWidget
+{
+Q_OBJECT
+Q_DECLARE_PRIVATE(QSGCanvas)
+public:
+ QSGCanvas(QWidget *parent = 0, Qt::WindowFlags f = 0);
+ QSGCanvas(const QGLFormat &format, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ virtual ~QSGCanvas();
+
+ QSGItem *rootItem() const;
+ QSGItem *activeFocusItem() const;
+
+ QSGItem *mouseGrabberItem() const;
+
+ bool sendEvent(QSGItem *, QEvent *);
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+ QSGEngine *sceneGraphEngine() const;
+
+signals:
+ void sceneGraphInitialized();
+
+protected:
+ QSGCanvas(QSGCanvasPrivate &dd, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ QSGCanvas(QSGCanvasPrivate &dd, const QGLFormat &format, QWidget *parent = 0, Qt::WindowFlags f = 0);
+
+ virtual void paintEvent(QPaintEvent *);
+ virtual void resizeEvent(QResizeEvent *);
+
+ virtual void showEvent(QShowEvent *);
+ virtual void hideEvent(QHideEvent *);
+
+ virtual bool event(QEvent *);
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void keyReleaseEvent(QKeyEvent *);
+ virtual void inputMethodEvent(QInputMethodEvent *);
+ virtual void mousePressEvent(QMouseEvent *);
+ virtual void mouseReleaseEvent(QMouseEvent *);
+ virtual void mouseDoubleClickEvent(QMouseEvent *);
+ virtual void mouseMoveEvent(QMouseEvent *);
+#ifndef QT_NO_WHEELEVENT
+ virtual void wheelEvent(QWheelEvent *);
+#endif
+
+private slots:
+ void sceneGraphChanged();
+ void maybeUpdate();
+
+private:
+ Q_DISABLE_COPY(QSGCanvas);
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QSGCanvas *);
+
+QT_END_HEADER
+
+#endif // QSGCANVAS_H
+
diff --git a/src/declarative/items/qsgcanvas_p.h b/src/declarative/items/qsgcanvas_p.h
new file mode 100644
index 0000000000..63bd2dfb28
--- /dev/null
+++ b/src/declarative/items/qsgcanvas_p.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCANVAS_P_H
+#define QSGCANVAS_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 "qsgitem.h"
+#include "qsgcanvas.h"
+#include <private/qdeclarativeguard_p.h>
+
+#include <private/qsgcontext_p.h>
+
+#include <QtCore/qthread.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <private/qwidget_p.h>
+#include <private/qgl_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//Make it easy to identify and customize the root item if needed
+class QSGRootItem : public QSGItem
+{
+ Q_OBJECT
+public:
+ QSGRootItem();
+};
+
+class QSGCanvasPrivate;
+
+class QSGThreadedRendererAnimationDriver : public QAnimationDriver
+{
+public:
+ QSGThreadedRendererAnimationDriver(QSGCanvasPrivate *r, QObject *parent);
+
+protected:
+ virtual void started();
+ virtual void stopped();
+
+ QSGCanvasPrivate *renderer;
+};
+
+class QTouchEvent;
+class QSGCanvasPrivate : public QGLWidgetPrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QSGCanvas)
+
+ static inline QSGCanvasPrivate *get(QSGCanvas *c) { return c->d_func(); }
+
+ QSGCanvasPrivate();
+ virtual ~QSGCanvasPrivate();
+
+ void init(QSGCanvas *);
+
+ QSGRootItem *rootItem;
+
+ QSGItem *activeFocusItem;
+ QSGItem *mouseGrabberItem;
+
+ // Mouse positions are saved in widget coordinates
+ QPoint lastMousePosition;
+ QPoint buttonDownPositions[5]; // Left, Right, Middle, XButton1, XButton2
+ void sceneMouseEventFromMouseEvent(QGraphicsSceneMouseEvent &, QMouseEvent *);
+ void translateTouchEvent(QTouchEvent *touchEvent);
+ static QEvent::Type sceneMouseEventTypeFromMouseEvent(QMouseEvent *);
+ static void sceneMouseEventForTransform(QGraphicsSceneMouseEvent &, const QTransform &);
+ static void transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform);
+ bool deliverInitialMousePressEvent(QSGItem *, QGraphicsSceneMouseEvent *);
+ bool deliverMouseEvent(QGraphicsSceneMouseEvent *);
+ bool sendFilteredMouseEvent(QSGItem *, QSGItem *, QGraphicsSceneMouseEvent *);
+ bool deliverWheelEvent(QSGItem *, QGraphicsSceneWheelEvent *);
+ bool deliverTouchPoints(QSGItem *, QTouchEvent *, const QList<QTouchEvent::TouchPoint> &, QSet<int> *,
+ QHash<QSGItem *, QList<QTouchEvent::TouchPoint> > *);
+ bool deliverTouchEvent(QTouchEvent *);
+ void sceneHoverEventFromMouseEvent(QGraphicsSceneHoverEvent &, QMouseEvent *);
+ bool deliverHoverEvent(QSGItem *, QGraphicsSceneHoverEvent *);
+ void sendHoverEvent(QEvent::Type, QSGItem *, QGraphicsSceneHoverEvent *);
+ void clearHover();
+
+ QDeclarativeGuard<QSGItem> hoverItem;
+ enum FocusOption {
+ DontChangeFocusProperty = 0x01,
+ };
+ Q_DECLARE_FLAGS(FocusOptions, FocusOption)
+
+ void setFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions = 0);
+ void clearFocusInScope(QSGItem *scope, QSGItem *item, FocusOptions = 0);
+ void notifyFocusChangesRecur(QSGItem **item, int remaining);
+
+ void updateInputMethodData();
+
+ void dirtyItem(QSGItem *);
+ void cleanup(QSGNode *);
+
+ void initializeSceneGraph();
+ void polishItems();
+ void syncSceneGraph();
+ void renderSceneGraph();
+ void runThread();
+
+ QSGItem::UpdatePaintNodeData updatePaintNodeData;
+
+ QSGItem *dirtyItemList;
+ QList<QSGNode *> cleanupNodeList;
+
+ QSet<QSGItem *> itemsToPolish;
+
+ void updateDirtyNodes();
+ void cleanupNodes();
+ bool updateEffectiveOpacity(QSGItem *);
+ void updateEffectiveOpacityRoot(QSGItem *, qreal);
+ void updateDirtyNode(QSGItem *);
+
+ QSGContext *context;
+
+ uint contextInThread : 1;
+ uint threadedRendering : 1;
+ uint exitThread : 1;
+ uint animationRunning: 1;
+ uint idle : 1; // Set to true when render thread sees no change and enters a wait()
+ uint needsRepaint : 1; // Set by callback from render if scene needs repainting.
+ uint renderThreadAwakened : 1;
+
+ struct MyThread : public QThread {
+ MyThread(QSGCanvasPrivate *r) : renderer(r) {}
+ virtual void run() { renderer->runThread(); }
+ static void doWait() { QThread::msleep(16); }
+ QSGCanvasPrivate *renderer;
+ };
+ MyThread *thread;
+ QMutex mutex;
+ QWaitCondition wait;
+ QSize widgetSize;
+ QSize viewportSize;
+
+ QAnimationDriver *animationDriver;
+
+ QHash<int, QSGItem *> itemForTouchPointId;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGCanvasPrivate::FocusOptions)
+
+QT_END_NAMESPACE
+
+#endif // QSGCANVAS_P_H
diff --git a/src/declarative/items/qsgclipnode.cpp b/src/declarative/items/qsgclipnode.cpp
new file mode 100644
index 0000000000..2e40972620
--- /dev/null
+++ b/src/declarative/items/qsgclipnode.cpp
@@ -0,0 +1,121 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qsgclipnode_p.h"
+
+#include <QtGui/qvector2d.h>
+#include <QtCore/qmath.h>
+
+QSGDefaultClipNode::QSGDefaultClipNode(const QRectF &rect)
+ : m_rect(rect)
+ , m_radius(0)
+ , m_dirty_geometry(true)
+ , m_geometry(QSGGeometry::defaultAttributes_Point2D(), 0)
+{
+ setGeometry(&m_geometry);
+ setIsRectangular(true);
+}
+
+void QSGDefaultClipNode::setRect(const QRectF &rect)
+{
+ m_rect = rect;
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultClipNode::setRadius(qreal radius)
+{
+ m_radius = radius;
+ m_dirty_geometry = true;
+ setIsRectangular(radius == 0);
+}
+
+void QSGDefaultClipNode::update()
+{
+ if (m_dirty_geometry) {
+ updateGeometry();
+ m_dirty_geometry = false;
+ }
+}
+
+void QSGDefaultClipNode::updateGeometry()
+{
+ QSGGeometry *g = geometry();
+
+ if (qFuzzyIsNull(m_radius)) {
+ g->allocate(4);
+ QSGGeometry::updateRectGeometry(g, m_rect);
+
+ } else {
+ int vertexCount = 0;
+
+ // Radius should never exceeds half of the width or half of the height
+ qreal radius = qMin(qMin(m_rect.width() / 2, m_rect.height() / 2), m_radius);
+ QRectF rect = m_rect;
+ rect.adjust(radius, radius, -radius, -radius);
+
+ int segments = qMin(30, qCeil(radius)); // Number of segments per corner.
+
+ g->allocate((segments + 1) * 2);
+
+ QVector2D *vertices = (QVector2D *)g->vertexData();
+
+ for (int part = 0; part < 2; ++part) {
+ for (int i = 0; i <= segments; ++i) {
+ //### Should change to calculate sin/cos only once.
+ qreal angle = qreal(0.5 * M_PI) * (part + i / qreal(segments));
+ qreal s = qFastSin(angle);
+ qreal c = qFastCos(angle);
+ qreal y = (part ? rect.bottom() : rect.top()) - radius * c; // current inner y-coordinate.
+ qreal lx = rect.left() - radius * s; // current inner left x-coordinate.
+ qreal rx = rect.right() + radius * s; // current inner right x-coordinate.
+
+ vertices[vertexCount++] = QVector2D(rx, y);
+ vertices[vertexCount++] = QVector2D(lx, y);
+ }
+ }
+
+ markDirty(DirtyGeometry);
+ }
+ setClipRect(m_rect);
+}
+
diff --git a/src/declarative/items/qsgclipnode_p.h b/src/declarative/items/qsgclipnode_p.h
new file mode 100644
index 0000000000..aa1d01efdd
--- /dev/null
+++ b/src/declarative/items/qsgclipnode_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCLIPNODE_P_H
+#define QSGCLIPNODE_P_H
+
+#include <qsgnode.h>
+
+class QSGDefaultClipNode : public QSGClipNode
+{
+public:
+ QSGDefaultClipNode(const QRectF &);
+
+ void setRect(const QRectF &);
+ QRectF rect() const { return m_rect; }
+
+ void setRadius(qreal radius);
+ qreal radius() const { return m_radius; }
+
+ virtual void update();
+
+private:
+ void updateGeometry();
+ QRectF m_rect;
+ qreal m_radius;
+
+ uint m_dirty_geometry : 1;
+ uint m_reserved : 31;
+
+ QSGGeometry m_geometry;
+};
+
+#endif // QSGCLIPNODE_P_H
diff --git a/src/declarative/items/qsgevents.cpp b/src/declarative/items/qsgevents.cpp
new file mode 100644
index 0000000000..44ef38b037
--- /dev/null
+++ b/src/declarative/items/qsgevents.cpp
@@ -0,0 +1,47 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgevents_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgevents_p_p.h b/src/declarative/items/qsgevents_p_p.h
new file mode 100644
index 0000000000..f0d434db32
--- /dev/null
+++ b/src/declarative/items/qsgevents_p_p.h
@@ -0,0 +1,142 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGEVENTS_P_P_H
+#define QSGEVENTS_P_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 <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGKeyEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int key READ key)
+ Q_PROPERTY(QString text READ text)
+ Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool isAutoRepeat READ isAutoRepeat)
+ Q_PROPERTY(int count READ count)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ QSGKeyEvent(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, const QString &text=QString(), bool autorep=false, ushort count=1)
+ : event(type, key, modifiers, text, autorep, count) { event.setAccepted(false); }
+ QSGKeyEvent(const QKeyEvent &ke)
+ : event(ke) { event.setAccepted(false); }
+
+ int key() const { return event.key(); }
+ QString text() const { return event.text(); }
+ int modifiers() const { return event.modifiers(); }
+ bool isAutoRepeat() const { return event.isAutoRepeat(); }
+ int count() const { return event.count(); }
+
+ bool isAccepted() { return event.isAccepted(); }
+ void setAccepted(bool accepted) { event.setAccepted(accepted); }
+
+private:
+ QKeyEvent event;
+};
+
+class QSGMouseEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int x READ x)
+ Q_PROPERTY(int y READ y)
+ Q_PROPERTY(int button READ button)
+ Q_PROPERTY(int buttons READ buttons)
+ Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool wasHeld READ wasHeld)
+ Q_PROPERTY(bool isClick READ isClick)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ QSGMouseEvent(int x, int y, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers
+ , bool isClick=false, bool wasHeld=false)
+ : _x(x), _y(y), _button(button), _buttons(buttons), _modifiers(modifiers)
+ , _wasHeld(wasHeld), _isClick(isClick), _accepted(true) {}
+
+ int x() const { return _x; }
+ int y() const { return _y; }
+ int button() const { return _button; }
+ int buttons() const { return _buttons; }
+ int modifiers() const { return _modifiers; }
+ bool wasHeld() const { return _wasHeld; }
+ bool isClick() const { return _isClick; }
+
+ // only for internal usage
+ void setX(int x) { _x = x; }
+ void setY(int y) { _y = y; }
+
+ bool isAccepted() { return _accepted; }
+ void setAccepted(bool accepted) { _accepted = accepted; }
+
+private:
+ int _x;
+ int _y;
+ Qt::MouseButton _button;
+ Qt::MouseButtons _buttons;
+ Qt::KeyboardModifiers _modifiers;
+ bool _wasHeld;
+ bool _isClick;
+ bool _accepted;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGKeyEvent)
+QML_DECLARE_TYPE(QSGMouseEvent)
+
+#endif // QSGEVENTS_P_P_H
diff --git a/src/declarative/items/qsgflickable.cpp b/src/declarative/items/qsgflickable.cpp
new file mode 100644
index 0000000000..e2f6fff71b
--- /dev/null
+++ b/src/declarative/items/qsgflickable.cpp
@@ -0,0 +1,1397 @@
+// Commit: ee767e8c16742316068e83323374ea54f2b939cb
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgflickable_p.h"
+#include "qsgflickable_p_p.h"
+#include "qsgcanvas.h"
+#include "qsgcanvas_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+// FlickThreshold determines how far the "mouse" must have moved
+// before we perform a flick.
+static const int FlickThreshold = 20;
+
+// RetainGrabVelocity is the maxmimum instantaneous velocity that
+// will ensure the Flickable retains the grab on consecutive flicks.
+static const int RetainGrabVelocity = 15;
+
+QSGFlickableVisibleArea::QSGFlickableVisibleArea(QSGFlickable *parent)
+ : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
+ , m_yPosition(0.), m_heightRatio(0.)
+{
+}
+
+qreal QSGFlickableVisibleArea::widthRatio() const
+{
+ return m_widthRatio;
+}
+
+qreal QSGFlickableVisibleArea::xPosition() const
+{
+ return m_xPosition;
+}
+
+qreal QSGFlickableVisibleArea::heightRatio() const
+{
+ return m_heightRatio;
+}
+
+qreal QSGFlickableVisibleArea::yPosition() const
+{
+ return m_yPosition;
+}
+
+void QSGFlickableVisibleArea::updateVisible()
+{
+ QSGFlickablePrivate *p = QSGFlickablePrivate::get(flickable);
+
+ bool changeX = false;
+ bool changeY = false;
+ bool changeWidth = false;
+ bool changeHeight = false;
+
+ // Vertical
+ const qreal viewheight = flickable->height();
+ const qreal maxyextent = -flickable->maxYExtent() + flickable->minYExtent();
+ qreal pagePos = (-p->vData.move.value() + flickable->minYExtent()) / (maxyextent + viewheight);
+ qreal pageSize = viewheight / (maxyextent + viewheight);
+
+ if (pageSize != m_heightRatio) {
+ m_heightRatio = pageSize;
+ changeHeight = true;
+ }
+ if (pagePos != m_yPosition) {
+ m_yPosition = pagePos;
+ changeY = true;
+ }
+
+ // Horizontal
+ const qreal viewwidth = flickable->width();
+ const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
+ pagePos = (-p->hData.move.value() + flickable->minXExtent()) / (maxxextent + viewwidth);
+ pageSize = viewwidth / (maxxextent + viewwidth);
+
+ if (pageSize != m_widthRatio) {
+ m_widthRatio = pageSize;
+ changeWidth = true;
+ }
+ if (pagePos != m_xPosition) {
+ m_xPosition = pagePos;
+ changeX = true;
+ }
+
+ if (changeX)
+ emit xPositionChanged(m_xPosition);
+ if (changeY)
+ emit yPositionChanged(m_yPosition);
+ if (changeWidth)
+ emit widthRatioChanged(m_widthRatio);
+ if (changeHeight)
+ emit heightRatioChanged(m_heightRatio);
+}
+
+
+QSGFlickablePrivate::QSGFlickablePrivate()
+ : contentItem(new QSGItem)
+ , hData(this, &QSGFlickablePrivate::setRoundedViewportX)
+ , vData(this, &QSGFlickablePrivate::setRoundedViewportY)
+ , flickingHorizontally(false), flickingVertically(false)
+ , hMoved(false), vMoved(false)
+ , movingHorizontally(false), movingVertically(false)
+ , stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
+ , deceleration(500), maxVelocity(2000), reportedVelocitySmoothing(100)
+ , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(600)
+ , fixupMode(Normal), vTime(0), visibleArea(0)
+ , flickableDirection(QSGFlickable::AutoFlickDirection)
+ , boundsBehavior(QSGFlickable::DragAndOvershootBounds)
+{
+}
+
+void QSGFlickablePrivate::init()
+{
+ Q_Q(QSGFlickable);
+ QDeclarative_setParent_noEvent(contentItem, q);
+ contentItem->setParentItem(q);
+ static int timelineUpdatedIdx = -1;
+ static int timelineCompletedIdx = -1;
+ static int flickableTickedIdx = -1;
+ static int flickableMovementEndingIdx = -1;
+ if (timelineUpdatedIdx == -1) {
+ timelineUpdatedIdx = QDeclarativeTimeLine::staticMetaObject.indexOfSignal("updated()");
+ timelineCompletedIdx = QDeclarativeTimeLine::staticMetaObject.indexOfSignal("completed()");
+ flickableTickedIdx = QSGFlickable::staticMetaObject.indexOfSlot("ticked()");
+ flickableMovementEndingIdx = QSGFlickable::staticMetaObject.indexOfSlot("movementEnding()");
+ }
+ QMetaObject::connect(&timeline, timelineUpdatedIdx,
+ q, flickableTickedIdx, Qt::DirectConnection);
+ QMetaObject::connect(&timeline, timelineCompletedIdx,
+ q, flickableMovementEndingIdx, Qt::DirectConnection);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFiltersChildMouseEvents(true);
+ QSGItemPrivate *viewportPrivate = QSGItemPrivate::get(contentItem);
+ viewportPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ lastPosTime.invalidate();
+}
+
+/*
+ Returns the amount to overshoot by given a velocity.
+ Will be roughly in range 0 - size/4
+*/
+qreal QSGFlickablePrivate::overShootDistance(qreal velocity, qreal size)
+{
+ if (maxVelocity <= 0)
+ return 0.0;
+
+ velocity = qAbs(velocity);
+ if (velocity > maxVelocity)
+ velocity = maxVelocity;
+ qreal dist = size / 4 * velocity / maxVelocity;
+ return dist;
+}
+
+void QSGFlickablePrivate::itemGeometryChanged(QSGItem *item, const QRectF &newGeom, const QRectF &oldGeom)
+{
+ Q_Q(QSGFlickable);
+ if (item == contentItem) {
+ if (newGeom.x() != oldGeom.x())
+ emit q->contentXChanged();
+ if (newGeom.y() != oldGeom.y())
+ emit q->contentYChanged();
+ }
+}
+
+void QSGFlickablePrivate::flickX(qreal velocity)
+{
+ Q_Q(QSGFlickable);
+ flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, velocity);
+}
+
+void QSGFlickablePrivate::flickY(qreal velocity)
+{
+ Q_Q(QSGFlickable);
+ flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity);
+}
+
+void QSGFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
+{
+ Q_Q(QSGFlickable);
+ qreal maxDistance = -1;
+ data.fixingUp = false;
+ bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
+ // -ve velocity means list is moving up
+ if (velocity > 0) {
+ if (data.move.value() < minExtent)
+ maxDistance = qAbs(minExtent - data.move.value() + (overShoot?overShootDistance(velocity,vSize):0));
+ data.flickTarget = minExtent;
+ } else {
+ if (data.move.value() > maxExtent)
+ maxDistance = qAbs(maxExtent - data.move.value()) + (overShoot?overShootDistance(velocity,vSize):0);
+ data.flickTarget = maxExtent;
+ }
+ if (maxDistance > 0) {
+ qreal v = velocity;
+ if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
+ if (v < 0)
+ v = -maxVelocity;
+ else
+ v = maxVelocity;
+ }
+ timeline.reset(data.move);
+ timeline.accel(data.move, v, deceleration, maxDistance);
+ timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
+ if (!flickingHorizontally && q->xflick()) {
+ flickingHorizontally = true;
+ emit q->flickingChanged();
+ emit q->flickingHorizontallyChanged();
+ if (!flickingVertically)
+ emit q->flickStarted();
+ }
+ if (!flickingVertically && q->yflick()) {
+ flickingVertically = true;
+ emit q->flickingChanged();
+ emit q->flickingVerticallyChanged();
+ if (!flickingHorizontally)
+ emit q->flickStarted();
+ }
+ } else {
+ timeline.reset(data.move);
+ fixup(data, minExtent, maxExtent);
+ }
+}
+
+void QSGFlickablePrivate::fixupY_callback(void *data)
+{
+ ((QSGFlickablePrivate *)data)->fixupY();
+}
+
+void QSGFlickablePrivate::fixupX_callback(void *data)
+{
+ ((QSGFlickablePrivate *)data)->fixupX();
+}
+
+void QSGFlickablePrivate::fixupX()
+{
+ Q_Q(QSGFlickable);
+ fixup(hData, q->minXExtent(), q->maxXExtent());
+}
+
+void QSGFlickablePrivate::fixupY()
+{
+ Q_Q(QSGFlickable);
+ fixup(vData, q->minYExtent(), q->maxYExtent());
+}
+
+void QSGFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
+{
+ if (data.move.value() > minExtent || maxExtent > minExtent) {
+ timeline.reset(data.move);
+ if (data.move.value() != minExtent) {
+ switch (fixupMode) {
+ case Immediate:
+ timeline.set(data.move, minExtent);
+ break;
+ case ExtentChanged:
+ // The target has changed. Don't start from the beginning; just complete the
+ // second half of the animation using the new extent.
+ timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ break;
+ default: {
+ qreal dist = minExtent - data.move;
+ timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
+ timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ }
+ }
+ }
+ } else if (data.move.value() < maxExtent) {
+ timeline.reset(data.move);
+ switch (fixupMode) {
+ case Immediate:
+ timeline.set(data.move, maxExtent);
+ break;
+ case ExtentChanged:
+ // The target has changed. Don't start from the beginning; just complete the
+ // second half of the animation using the new extent.
+ timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ break;
+ default: {
+ qreal dist = maxExtent - data.move;
+ timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
+ timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ }
+ }
+ }
+ fixupMode = Normal;
+ vTime = timeline.time();
+}
+
+void QSGFlickablePrivate::updateBeginningEnd()
+{
+ Q_Q(QSGFlickable);
+ bool atBoundaryChange = false;
+
+ // Vertical
+ const int maxyextent = int(-q->maxYExtent());
+ const qreal ypos = -vData.move.value();
+ bool atBeginning = (ypos <= -q->minYExtent());
+ bool atEnd = (maxyextent <= ypos);
+
+ if (atBeginning != vData.atBeginning) {
+ vData.atBeginning = atBeginning;
+ atBoundaryChange = true;
+ }
+ if (atEnd != vData.atEnd) {
+ vData.atEnd = atEnd;
+ atBoundaryChange = true;
+ }
+
+ // Horizontal
+ const int maxxextent = int(-q->maxXExtent());
+ const qreal xpos = -hData.move.value();
+ atBeginning = (xpos <= -q->minXExtent());
+ atEnd = (maxxextent <= xpos);
+
+ if (atBeginning != hData.atBeginning) {
+ hData.atBeginning = atBeginning;
+ atBoundaryChange = true;
+ }
+ if (atEnd != hData.atEnd) {
+ hData.atEnd = atEnd;
+ atBoundaryChange = true;
+ }
+
+ if (atBoundaryChange)
+ emit q->isAtBoundaryChanged();
+
+ if (visibleArea)
+ visibleArea->updateVisible();
+}
+
+QSGFlickable::QSGFlickable(QSGItem *parent)
+ : QSGItem(*(new QSGFlickablePrivate), parent)
+{
+ Q_D(QSGFlickable);
+ d->init();
+}
+
+QSGFlickable::QSGFlickable(QSGFlickablePrivate &dd, QSGItem *parent)
+ : QSGItem(dd, parent)
+{
+ Q_D(QSGFlickable);
+ d->init();
+}
+
+QSGFlickable::~QSGFlickable()
+{
+}
+
+qreal QSGFlickable::contentX() const
+{
+ Q_D(const QSGFlickable);
+ return -d->contentItem->x();
+}
+
+void QSGFlickable::setContentX(qreal pos)
+{
+ Q_D(QSGFlickable);
+ d->timeline.reset(d->hData.move);
+ d->vTime = d->timeline.time();
+ movementXEnding();
+ if (-pos != d->hData.move.value()) {
+ d->hData.move.setValue(-pos);
+ viewportMoved();
+ }
+}
+
+qreal QSGFlickable::contentY() const
+{
+ Q_D(const QSGFlickable);
+ return -d->contentItem->y();
+}
+
+void QSGFlickable::setContentY(qreal pos)
+{
+ Q_D(QSGFlickable);
+ d->timeline.reset(d->vData.move);
+ d->vTime = d->timeline.time();
+ movementYEnding();
+ if (-pos != d->vData.move.value()) {
+ d->vData.move.setValue(-pos);
+ viewportMoved();
+ }
+}
+
+bool QSGFlickable::isInteractive() const
+{
+ Q_D(const QSGFlickable);
+ return d->interactive;
+}
+
+void QSGFlickable::setInteractive(bool interactive)
+{
+ Q_D(QSGFlickable);
+ if (interactive != d->interactive) {
+ d->interactive = interactive;
+ if (!interactive && (d->flickingHorizontally || d->flickingVertically)) {
+ d->timeline.clear();
+ d->vTime = d->timeline.time();
+ d->flickingHorizontally = false;
+ d->flickingVertically = false;
+ emit flickingChanged();
+ emit flickingHorizontallyChanged();
+ emit flickingVerticallyChanged();
+ emit flickEnded();
+ }
+ emit interactiveChanged();
+ }
+}
+
+qreal QSGFlickable::horizontalVelocity() const
+{
+ Q_D(const QSGFlickable);
+ return d->hData.smoothVelocity.value();
+}
+
+qreal QSGFlickable::verticalVelocity() const
+{
+ Q_D(const QSGFlickable);
+ return d->vData.smoothVelocity.value();
+}
+
+bool QSGFlickable::isAtXEnd() const
+{
+ Q_D(const QSGFlickable);
+ return d->hData.atEnd;
+}
+
+bool QSGFlickable::isAtXBeginning() const
+{
+ Q_D(const QSGFlickable);
+ return d->hData.atBeginning;
+}
+
+bool QSGFlickable::isAtYEnd() const
+{
+ Q_D(const QSGFlickable);
+ return d->vData.atEnd;
+}
+
+bool QSGFlickable::isAtYBeginning() const
+{
+ Q_D(const QSGFlickable);
+ return d->vData.atBeginning;
+}
+
+void QSGFlickable::ticked()
+{
+ viewportMoved();
+}
+
+QSGItem *QSGFlickable::contentItem()
+{
+ Q_D(QSGFlickable);
+ return d->contentItem;
+}
+
+QSGFlickableVisibleArea *QSGFlickable::visibleArea()
+{
+ Q_D(QSGFlickable);
+ if (!d->visibleArea)
+ d->visibleArea = new QSGFlickableVisibleArea(this);
+ return d->visibleArea;
+}
+
+QSGFlickable::FlickableDirection QSGFlickable::flickableDirection() const
+{
+ Q_D(const QSGFlickable);
+ return d->flickableDirection;
+}
+
+void QSGFlickable::setFlickableDirection(FlickableDirection direction)
+{
+ Q_D(QSGFlickable);
+ if (direction != d->flickableDirection) {
+ d->flickableDirection = direction;
+ emit flickableDirectionChanged();
+ }
+}
+
+void QSGFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGFlickable);
+ if (interactive && timeline.isActive()
+ && (qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity
+ || qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity)) {
+ stealMouse = true; // If we've been flicked then steal the click.
+ } else {
+ stealMouse = false;
+ }
+ q->setKeepMouseGrab(stealMouse);
+ pressed = true;
+ timeline.clear();
+ hData.velocity = 0;
+ vData.velocity = 0;
+ hData.dragStartOffset = 0;
+ vData.dragStartOffset = 0;
+ hData.dragMinBound = q->minXExtent();
+ vData.dragMinBound = q->minYExtent();
+ hData.dragMaxBound = q->maxXExtent();
+ vData.dragMaxBound = q->maxYExtent();
+ hData.fixingUp = false;
+ vData.fixingUp = false;
+ lastPos = QPoint();
+ QSGItemPrivate::start(lastPosTime);
+ pressPos = event->pos();
+ hData.pressPos = hData.move.value();
+ vData.pressPos = vData.move.value();
+ flickingHorizontally = false;
+ flickingVertically = false;
+ QSGItemPrivate::start(pressTime);
+ QSGItemPrivate::start(velocityTime);
+}
+
+void QSGFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGFlickable);
+ if (!interactive || !lastPosTime.isValid())
+ return;
+ bool rejectY = false;
+ bool rejectX = false;
+
+ bool stealY = stealMouse;
+ bool stealX = stealMouse;
+
+ if (q->yflick()) {
+ int dy = int(event->pos().y() - pressPos.y());
+ if (qAbs(dy) > QApplication::startDragDistance() || QSGItemPrivate::elapsed(pressTime) > 200) {
+ if (!vMoved)
+ vData.dragStartOffset = dy;
+ qreal newY = dy + vData.pressPos - vData.dragStartOffset;
+ const qreal minY = vData.dragMinBound;
+ const qreal maxY = vData.dragMaxBound;
+ if (newY > minY)
+ newY = minY + (newY - minY) / 2;
+ if (newY < maxY && maxY - minY <= 0)
+ newY = maxY + (newY - maxY) / 2;
+ if (boundsBehavior == QSGFlickable::StopAtBounds && (newY > minY || newY < maxY)) {
+ rejectY = true;
+ if (newY < maxY) {
+ newY = maxY;
+ rejectY = false;
+ }
+ if (newY > minY) {
+ newY = minY;
+ rejectY = false;
+ }
+ }
+ if (!rejectY && stealMouse) {
+ vData.move.setValue(qRound(newY));
+ vMoved = true;
+ }
+ if (qAbs(dy) > QApplication::startDragDistance())
+ stealY = true;
+ }
+ }
+
+ if (q->xflick()) {
+ int dx = int(event->pos().x() - pressPos.x());
+ if (qAbs(dx) > QApplication::startDragDistance() || QSGItemPrivate::elapsed(pressTime) > 200) {
+ if (!hMoved)
+ hData.dragStartOffset = dx;
+ qreal newX = dx + hData.pressPos - hData.dragStartOffset;
+ const qreal minX = hData.dragMinBound;
+ const qreal maxX = hData.dragMaxBound;
+ if (newX > minX)
+ newX = minX + (newX - minX) / 2;
+ if (newX < maxX && maxX - minX <= 0)
+ newX = maxX + (newX - maxX) / 2;
+ if (boundsBehavior == QSGFlickable::StopAtBounds && (newX > minX || newX < maxX)) {
+ rejectX = true;
+ if (newX < maxX) {
+ newX = maxX;
+ rejectX = false;
+ }
+ if (newX > minX) {
+ newX = minX;
+ rejectX = false;
+ }
+ }
+ if (!rejectX && stealMouse) {
+ hData.move.setValue(qRound(newX));
+ hMoved = true;
+ }
+
+ if (qAbs(dx) > QApplication::startDragDistance())
+ stealX = true;
+ }
+ }
+
+ stealMouse = stealX || stealY;
+ if (stealMouse)
+ q->setKeepMouseGrab(true);
+
+ if (!lastPos.isNull()) {
+ qreal elapsed = qreal(QSGItemPrivate::restart(lastPosTime)) / 1000.;
+ if (elapsed <= 0)
+ elapsed = 1;
+ if (q->yflick()) {
+ qreal diff = event->pos().y() - lastPos.y();
+ // average to reduce the effect of spurious moves
+ vData.velocity += diff / elapsed;
+ vData.velocity /= 2;
+ }
+
+ if (q->xflick()) {
+ qreal diff = event->pos().x() - lastPos.x();
+ // average to reduce the effect of spurious moves
+ hData.velocity += diff / elapsed;
+ hData.velocity /= 2;
+ }
+ }
+
+ if (rejectY) vData.velocity = 0;
+ if (rejectX) hData.velocity = 0;
+
+ if (hMoved || vMoved) {
+ q->movementStarting();
+ q->viewportMoved();
+ }
+
+ lastPos = event->pos();
+}
+
+void QSGFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGFlickable);
+ stealMouse = false;
+ q->setKeepMouseGrab(false);
+ pressed = false;
+ if (!lastPosTime.isValid())
+ return;
+
+ if (QSGItemPrivate::elapsed(lastPosTime) > 100) {
+ // if we drag then pause before release we should not cause a flick.
+ hData.velocity = 0.0;
+ vData.velocity = 0.0;
+ }
+
+ vTime = timeline.time();
+ if (qAbs(vData.velocity) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos.y()) > FlickThreshold)
+ flickY(vData.velocity);
+ else
+ fixupY();
+
+ if (qAbs(hData.velocity) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos.x()) > FlickThreshold)
+ flickX(hData.velocity);
+ else
+ fixupX();
+
+ lastPosTime.invalidate();
+
+ if (!timeline.isActive())
+ q->movementEnding();
+}
+
+void QSGFlickable::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGFlickable);
+ if (d->interactive) {
+ if (!d->pressed)
+ d->handleMousePressEvent(event);
+ event->accept();
+ } else {
+ QSGItem::mousePressEvent(event);
+ }
+}
+
+void QSGFlickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGFlickable);
+ if (d->interactive) {
+ d->handleMouseMoveEvent(event);
+ event->accept();
+ } else {
+ QSGItem::mouseMoveEvent(event);
+ }
+}
+
+void QSGFlickable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGFlickable);
+ if (d->interactive) {
+ d->clearDelayedPress();
+ d->handleMouseReleaseEvent(event);
+ event->accept();
+ ungrabMouse();
+ } else {
+ QSGItem::mouseReleaseEvent(event);
+ }
+}
+
+void QSGFlickable::wheelEvent(QGraphicsSceneWheelEvent *event)
+{
+ Q_D(QSGFlickable);
+ if (!d->interactive) {
+ QSGItem::wheelEvent(event);
+ } else if (yflick() && event->orientation() == Qt::Vertical) {
+ if (event->delta() > 0)
+ d->vData.velocity = qMax(event->delta() - d->vData.smoothVelocity.value(), qreal(250.0));
+ else
+ d->vData.velocity = qMin(event->delta() - d->vData.smoothVelocity.value(), qreal(-250.0));
+ d->flickingVertically = false;
+ d->flickY(d->vData.velocity);
+ if (d->flickingVertically) {
+ d->vMoved = true;
+ movementStarting();
+ }
+ event->accept();
+ } else if (xflick() && event->orientation() == Qt::Horizontal) {
+ if (event->delta() > 0)
+ d->hData.velocity = qMax(event->delta() - d->hData.smoothVelocity.value(), qreal(250.0));
+ else
+ d->hData.velocity = qMin(event->delta() - d->hData.smoothVelocity.value(), qreal(-250.0));
+ d->flickingHorizontally = false;
+ d->flickX(d->hData.velocity);
+ if (d->flickingHorizontally) {
+ d->hMoved = true;
+ movementStarting();
+ }
+ event->accept();
+ } else {
+ QSGItem::wheelEvent(event);
+ }
+}
+
+bool QSGFlickablePrivate::isOutermostPressDelay() const
+{
+ Q_Q(const QSGFlickable);
+ QSGItem *item = q->parentItem();
+ while (item) {
+ QSGFlickable *flick = qobject_cast<QSGFlickable*>(item);
+ if (flick && flick->pressDelay() > 0 && flick->isInteractive())
+ return false;
+ item = item->parentItem();
+ }
+
+ return true;
+}
+
+void QSGFlickablePrivate::captureDelayedPress(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGFlickable);
+ if (!q->canvas() || pressDelay <= 0)
+ return;
+ if (!isOutermostPressDelay())
+ return;
+ delayedPressTarget = q->canvas()->mouseGrabberItem();
+ delayedPressEvent = new QGraphicsSceneMouseEvent(event->type());
+ delayedPressEvent->setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ delayedPressEvent->setButtonDownPos(button, event->buttonDownPos(button));
+ delayedPressEvent->setButtonDownScenePos(button, event->buttonDownScenePos(button));
+ delayedPressEvent->setButtonDownScreenPos(button, event->buttonDownScreenPos(button));
+ }
+ }
+ delayedPressEvent->setButtons(event->buttons());
+ delayedPressEvent->setButton(event->button());
+ delayedPressEvent->setPos(event->pos());
+ delayedPressEvent->setScenePos(event->scenePos());
+ delayedPressEvent->setScreenPos(event->screenPos());
+ delayedPressEvent->setLastPos(event->lastPos());
+ delayedPressEvent->setLastScenePos(event->lastScenePos());
+ delayedPressEvent->setLastScreenPos(event->lastScreenPos());
+ delayedPressEvent->setModifiers(event->modifiers());
+ delayedPressTimer.start(pressDelay, q);
+}
+
+void QSGFlickablePrivate::clearDelayedPress()
+{
+ if (delayedPressEvent) {
+ delayedPressTimer.stop();
+ delete delayedPressEvent;
+ delayedPressEvent = 0;
+ }
+}
+
+void QSGFlickablePrivate::setRoundedViewportX(qreal x)
+{
+ contentItem->setX(qRound(x));
+}
+
+void QSGFlickablePrivate::setRoundedViewportY(qreal y)
+{
+ contentItem->setY(qRound(y));
+}
+
+void QSGFlickable::timerEvent(QTimerEvent *event)
+{
+ Q_D(QSGFlickable);
+ if (event->timerId() == d->delayedPressTimer.timerId()) {
+ d->delayedPressTimer.stop();
+ if (d->delayedPressEvent) {
+ QSGItem *grabber = canvas() ? canvas()->mouseGrabberItem() : 0;
+ if (!grabber || grabber != this) {
+ // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
+ // so we reset the grabber
+ if (canvas()->mouseGrabberItem() == d->delayedPressTarget)
+ d->delayedPressTarget->ungrabMouse();
+ // Use the event handler that will take care of finding the proper item to propagate the event
+ QSGCanvasPrivate::get(canvas())->deliverMouseEvent(d->delayedPressEvent);
+ }
+ delete d->delayedPressEvent;
+ d->delayedPressEvent = 0;
+ }
+ }
+}
+
+qreal QSGFlickable::minYExtent() const
+{
+ return 0.0;
+}
+
+qreal QSGFlickable::minXExtent() const
+{
+ return 0.0;
+}
+
+/* returns -ve */
+qreal QSGFlickable::maxXExtent() const
+{
+ return width() - vWidth();
+}
+/* returns -ve */
+qreal QSGFlickable::maxYExtent() const
+{
+ return height() - vHeight();
+}
+
+void QSGFlickable::viewportMoved()
+{
+ Q_D(QSGFlickable);
+
+ qreal prevX = d->lastFlickablePosition.x();
+ qreal prevY = d->lastFlickablePosition.y();
+ d->velocityTimeline.clear();
+ if (d->pressed || d->calcVelocity) {
+ int elapsed = QSGItemPrivate::restart(d->velocityTime);
+ if (elapsed > 0) {
+ qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / elapsed;
+ qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / elapsed;
+ d->velocityTimeline.move(d->hData.smoothVelocity, horizontalVelocity, d->reportedVelocitySmoothing);
+ d->velocityTimeline.move(d->hData.smoothVelocity, 0, d->reportedVelocitySmoothing);
+ d->velocityTimeline.move(d->vData.smoothVelocity, verticalVelocity, d->reportedVelocitySmoothing);
+ d->velocityTimeline.move(d->vData.smoothVelocity, 0, d->reportedVelocitySmoothing);
+ }
+ } else {
+ if (d->timeline.time() > d->vTime) {
+ qreal horizontalVelocity = (prevX - d->hData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
+ qreal verticalVelocity = (prevY - d->vData.move.value()) * 1000 / (d->timeline.time() - d->vTime);
+ d->hData.smoothVelocity.setValue(horizontalVelocity);
+ d->vData.smoothVelocity.setValue(verticalVelocity);
+ }
+ }
+
+ d->lastFlickablePosition = QPointF(d->hData.move.value(), d->vData.move.value());
+
+ d->vTime = d->timeline.time();
+ d->updateBeginningEnd();
+}
+
+void QSGFlickable::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QSGFlickable);
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+
+ bool changed = false;
+ if (newGeometry.width() != oldGeometry.width()) {
+ if (xflick())
+ changed = true;
+ if (d->hData.viewSize < 0) {
+ d->contentItem->setWidth(width());
+ emit contentWidthChanged();
+ }
+ // Make sure that we're entirely in view.
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupX();
+ }
+ }
+ if (newGeometry.height() != oldGeometry.height()) {
+ if (yflick())
+ changed = true;
+ if (d->vData.viewSize < 0) {
+ d->contentItem->setHeight(height());
+ emit contentHeightChanged();
+ }
+ // Make sure that we're entirely in view.
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupY();
+ }
+ }
+
+ if (changed)
+ d->updateBeginningEnd();
+}
+
+void QSGFlickable::cancelFlick()
+{
+ Q_D(QSGFlickable);
+ d->timeline.reset(d->hData.move);
+ d->timeline.reset(d->vData.move);
+ movementEnding();
+}
+
+void QSGFlickablePrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
+{
+ QSGItem *i = qobject_cast<QSGItem *>(o);
+ if (i) {
+ i->setParentItem(static_cast<QSGFlickablePrivate*>(prop->data)->contentItem);
+ } else {
+ o->setParent(prop->object); // XXX todo - do we want this?
+ }
+}
+
+int QSGFlickablePrivate::data_count(QDeclarativeListProperty<QObject> *)
+{
+ // XXX todo
+ return 0;
+}
+
+QObject *QSGFlickablePrivate::data_at(QDeclarativeListProperty<QObject> *, int)
+{
+ // XXX todo
+ return 0;
+}
+
+void QSGFlickablePrivate::data_clear(QDeclarativeListProperty<QObject> *)
+{
+ // XXX todo
+}
+
+QDeclarativeListProperty<QObject> QSGFlickable::flickableData()
+{
+ Q_D(QSGFlickable);
+ return QDeclarativeListProperty<QObject>(this, (void *)d, QSGFlickablePrivate::data_append,
+ QSGFlickablePrivate::data_count,
+ QSGFlickablePrivate::data_at,
+ QSGFlickablePrivate::data_clear);
+}
+
+QDeclarativeListProperty<QSGItem> QSGFlickable::flickableChildren()
+{
+ Q_D(QSGFlickable);
+ return QSGItemPrivate::get(d->contentItem)->children();
+}
+
+QSGFlickable::BoundsBehavior QSGFlickable::boundsBehavior() const
+{
+ Q_D(const QSGFlickable);
+ return d->boundsBehavior;
+}
+
+void QSGFlickable::setBoundsBehavior(BoundsBehavior b)
+{
+ Q_D(QSGFlickable);
+ if (b == d->boundsBehavior)
+ return;
+ d->boundsBehavior = b;
+ emit boundsBehaviorChanged();
+}
+
+qreal QSGFlickable::contentWidth() const
+{
+ Q_D(const QSGFlickable);
+ return d->hData.viewSize;
+}
+
+void QSGFlickable::setContentWidth(qreal w)
+{
+ Q_D(QSGFlickable);
+ if (d->hData.viewSize == w)
+ return;
+ d->hData.viewSize = w;
+ if (w < 0)
+ d->contentItem->setWidth(width());
+ else
+ d->contentItem->setWidth(w);
+ // Make sure that we're entirely in view.
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupX();
+ } else if (!d->pressed && d->hData.fixingUp) {
+ d->fixupMode = QSGFlickablePrivate::ExtentChanged;
+ d->fixupX();
+ }
+ emit contentWidthChanged();
+ d->updateBeginningEnd();
+}
+
+qreal QSGFlickable::contentHeight() const
+{
+ Q_D(const QSGFlickable);
+ return d->vData.viewSize;
+}
+
+void QSGFlickable::setContentHeight(qreal h)
+{
+ Q_D(QSGFlickable);
+ if (d->vData.viewSize == h)
+ return;
+ d->vData.viewSize = h;
+ if (h < 0)
+ d->contentItem->setHeight(height());
+ else
+ d->contentItem->setHeight(h);
+ // Make sure that we're entirely in view.
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupY();
+ } else if (!d->pressed && d->vData.fixingUp) {
+ d->fixupMode = QSGFlickablePrivate::ExtentChanged;
+ d->fixupY();
+ }
+ emit contentHeightChanged();
+ d->updateBeginningEnd();
+}
+
+void QSGFlickable::resizeContent(qreal w, qreal h, QPointF center)
+{
+ Q_D(QSGFlickable);
+ if (w != d->hData.viewSize) {
+ qreal oldSize = d->hData.viewSize;
+ setContentWidth(w);
+ if (center.x() != 0) {
+ qreal pos = center.x() * w / oldSize;
+ setContentX(contentX() + pos - center.x());
+ }
+ }
+ if (h != d->vData.viewSize) {
+ qreal oldSize = d->vData.viewSize;
+ setContentHeight(h);
+ if (center.y() != 0) {
+ qreal pos = center.y() * h / oldSize;
+ setContentY(contentY() + pos - center.y());
+ }
+ }
+}
+
+void QSGFlickable::returnToBounds()
+{
+ Q_D(QSGFlickable);
+ d->fixupX();
+ d->fixupY();
+}
+
+qreal QSGFlickable::vWidth() const
+{
+ Q_D(const QSGFlickable);
+ if (d->hData.viewSize < 0)
+ return width();
+ else
+ return d->hData.viewSize;
+}
+
+qreal QSGFlickable::vHeight() const
+{
+ Q_D(const QSGFlickable);
+ if (d->vData.viewSize < 0)
+ return height();
+ else
+ return d->vData.viewSize;
+}
+
+bool QSGFlickable::xflick() const
+{
+ Q_D(const QSGFlickable);
+ if (d->flickableDirection == QSGFlickable::AutoFlickDirection)
+ return vWidth() != width();
+ return d->flickableDirection & QSGFlickable::HorizontalFlick;
+}
+
+bool QSGFlickable::yflick() const
+{
+ Q_D(const QSGFlickable);
+ if (d->flickableDirection == QSGFlickable::AutoFlickDirection)
+ return vHeight() != height();
+ return d->flickableDirection & QSGFlickable::VerticalFlick;
+}
+
+void QSGFlickable::mouseUngrabEvent()
+{
+ Q_D(QSGFlickable);
+ if (d->pressed) {
+ // if our mouse grab has been removed (probably by another Flickable),
+ // fix our state
+ d->pressed = false;
+ d->stealMouse = false;
+ setKeepMouseGrab(false);
+ }
+}
+
+bool QSGFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGFlickable);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+
+ QSGCanvas *c = canvas();
+ QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ d->handleMouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ if (d->pressed) // we are already pressed - this is a delayed replay
+ return false;
+
+ d->handleMousePressEvent(&mouseEvent);
+ d->captureDelayedPress(event);
+ stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ if (d->delayedPressEvent) {
+ // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
+ // so we reset the grabber
+ if (c->mouseGrabberItem() == d->delayedPressTarget)
+ d->delayedPressTarget->ungrabMouse();
+ //Use the event handler that will take care of finding the proper item to propagate the event
+ QSGCanvasPrivate::get(canvas())->deliverMouseEvent(d->delayedPressEvent);
+ d->clearDelayedPress();
+ // We send the release
+ canvas()->sendEvent(c->mouseGrabberItem(), event);
+ // And the event has been consumed
+ d->stealMouse = false;
+ d->pressed = false;
+ return true;
+ }
+ d->handleMouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = qobject_cast<QSGItem*>(c->mouseGrabberItem());
+ if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) {
+ d->clearDelayedPress();
+ grabMouse();
+ }
+
+ return stealThisEvent || d->delayedPressEvent;
+ } else if (d->lastPosTime.isValid()) {
+ d->lastPosTime.invalidate();
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+ d->clearDelayedPress();
+ d->stealMouse = false;
+ d->pressed = false;
+ }
+ return false;
+}
+
+
+bool QSGFlickable::childMouseEventFilter(QSGItem *i, QEvent *e)
+{
+ Q_D(QSGFlickable);
+ if (!isVisible() || !d->interactive)
+ return QSGItem::childMouseEventFilter(i, e);
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ default:
+ break;
+ }
+
+ return QSGItem::childMouseEventFilter(i, e);
+}
+
+qreal QSGFlickable::maximumFlickVelocity() const
+{
+ Q_D(const QSGFlickable);
+ return d->maxVelocity;
+}
+
+void QSGFlickable::setMaximumFlickVelocity(qreal v)
+{
+ Q_D(QSGFlickable);
+ if (v == d->maxVelocity)
+ return;
+ d->maxVelocity = v;
+ emit maximumFlickVelocityChanged();
+}
+
+qreal QSGFlickable::flickDeceleration() const
+{
+ Q_D(const QSGFlickable);
+ return d->deceleration;
+}
+
+void QSGFlickable::setFlickDeceleration(qreal deceleration)
+{
+ Q_D(QSGFlickable);
+ if (deceleration == d->deceleration)
+ return;
+ d->deceleration = deceleration;
+ emit flickDecelerationChanged();
+}
+
+bool QSGFlickable::isFlicking() const
+{
+ Q_D(const QSGFlickable);
+ return d->flickingHorizontally || d->flickingVertically;
+}
+
+bool QSGFlickable::isFlickingHorizontally() const
+{
+ Q_D(const QSGFlickable);
+ return d->flickingHorizontally;
+}
+
+bool QSGFlickable::isFlickingVertically() const
+{
+ Q_D(const QSGFlickable);
+ return d->flickingVertically;
+}
+
+int QSGFlickable::pressDelay() const
+{
+ Q_D(const QSGFlickable);
+ return d->pressDelay;
+}
+
+void QSGFlickable::setPressDelay(int delay)
+{
+ Q_D(QSGFlickable);
+ if (d->pressDelay == delay)
+ return;
+ d->pressDelay = delay;
+ emit pressDelayChanged();
+}
+
+
+bool QSGFlickable::isMoving() const
+{
+ Q_D(const QSGFlickable);
+ return d->movingHorizontally || d->movingVertically;
+}
+
+bool QSGFlickable::isMovingHorizontally() const
+{
+ Q_D(const QSGFlickable);
+ return d->movingHorizontally;
+}
+
+bool QSGFlickable::isMovingVertically() const
+{
+ Q_D(const QSGFlickable);
+ return d->movingVertically;
+}
+
+void QSGFlickable::movementStarting()
+{
+ Q_D(QSGFlickable);
+ if (d->hMoved && !d->movingHorizontally) {
+ d->movingHorizontally = true;
+ emit movingChanged();
+ emit movingHorizontallyChanged();
+ if (!d->movingVertically)
+ emit movementStarted();
+ }
+ else if (d->vMoved && !d->movingVertically) {
+ d->movingVertically = true;
+ emit movingChanged();
+ emit movingVerticallyChanged();
+ if (!d->movingHorizontally)
+ emit movementStarted();
+ }
+}
+
+void QSGFlickable::movementEnding()
+{
+ Q_D(QSGFlickable);
+ movementXEnding();
+ movementYEnding();
+ d->hData.smoothVelocity.setValue(0);
+ d->vData.smoothVelocity.setValue(0);
+}
+
+void QSGFlickable::movementXEnding()
+{
+ Q_D(QSGFlickable);
+ if (d->flickingHorizontally) {
+ d->flickingHorizontally = false;
+ emit flickingChanged();
+ emit flickingHorizontallyChanged();
+ if (!d->flickingVertically)
+ emit flickEnded();
+ }
+ if (!d->pressed && !d->stealMouse) {
+ if (d->movingHorizontally) {
+ d->movingHorizontally = false;
+ d->hMoved = false;
+ emit movingChanged();
+ emit movingHorizontallyChanged();
+ if (!d->movingVertically)
+ emit movementEnded();
+ }
+ }
+ d->hData.fixingUp = false;
+}
+
+void QSGFlickable::movementYEnding()
+{
+ Q_D(QSGFlickable);
+ if (d->flickingVertically) {
+ d->flickingVertically = false;
+ emit flickingChanged();
+ emit flickingVerticallyChanged();
+ if (!d->flickingHorizontally)
+ emit flickEnded();
+ }
+ if (!d->pressed && !d->stealMouse) {
+ if (d->movingVertically) {
+ d->movingVertically = false;
+ d->vMoved = false;
+ emit movingChanged();
+ emit movingVerticallyChanged();
+ if (!d->movingHorizontally)
+ emit movementEnded();
+ }
+ }
+ d->vData.fixingUp = false;
+}
+
+void QSGFlickablePrivate::updateVelocity()
+{
+ Q_Q(QSGFlickable);
+ emit q->horizontalVelocityChanged();
+ emit q->verticalVelocityChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgflickable_p.h b/src/declarative/items/qsgflickable_p.h
new file mode 100644
index 0000000000..c1ed024527
--- /dev/null
+++ b/src/declarative/items/qsgflickable_p.h
@@ -0,0 +1,230 @@
+// Commit: 1bcddaaf318fc37c71c5191913f3487c49444ec6
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFLICKABLE_P_H
+#define QSGFLICKABLE_P_H
+
+#include "qsgitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGFlickablePrivate;
+class QSGFlickableVisibleArea;
+class Q_AUTOTEST_EXPORT QSGFlickable : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged)
+ Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged)
+ Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged)
+ Q_PROPERTY(qreal contentY READ contentY WRITE setContentY NOTIFY contentYChanged)
+ Q_PROPERTY(QSGItem *contentItem READ contentItem CONSTANT)
+
+ Q_PROPERTY(qreal horizontalVelocity READ horizontalVelocity NOTIFY horizontalVelocityChanged)
+ Q_PROPERTY(qreal verticalVelocity READ verticalVelocity NOTIFY verticalVelocityChanged)
+
+ Q_PROPERTY(BoundsBehavior boundsBehavior READ boundsBehavior WRITE setBoundsBehavior NOTIFY boundsBehaviorChanged)
+ Q_PROPERTY(qreal maximumFlickVelocity READ maximumFlickVelocity WRITE setMaximumFlickVelocity NOTIFY maximumFlickVelocityChanged)
+ Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
+ Q_PROPERTY(bool moving READ isMoving NOTIFY movingChanged)
+ Q_PROPERTY(bool movingHorizontally READ isMovingHorizontally NOTIFY movingHorizontallyChanged)
+ Q_PROPERTY(bool movingVertically READ isMovingVertically NOTIFY movingVerticallyChanged)
+ Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged)
+ Q_PROPERTY(bool flickingHorizontally READ isFlickingHorizontally NOTIFY flickingHorizontallyChanged)
+ Q_PROPERTY(bool flickingVertically READ isFlickingVertically NOTIFY flickingVerticallyChanged)
+ Q_PROPERTY(FlickableDirection flickableDirection READ flickableDirection WRITE setFlickableDirection NOTIFY flickableDirectionChanged)
+
+ Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged)
+ Q_PROPERTY(int pressDelay READ pressDelay WRITE setPressDelay NOTIFY pressDelayChanged)
+
+ Q_PROPERTY(bool atXEnd READ isAtXEnd NOTIFY isAtBoundaryChanged)
+ Q_PROPERTY(bool atYEnd READ isAtYEnd NOTIFY isAtBoundaryChanged)
+ Q_PROPERTY(bool atXBeginning READ isAtXBeginning NOTIFY isAtBoundaryChanged)
+ Q_PROPERTY(bool atYBeginning READ isAtYBeginning NOTIFY isAtBoundaryChanged)
+
+ Q_PROPERTY(QSGFlickableVisibleArea *visibleArea READ visibleArea CONSTANT)
+
+ Q_PROPERTY(QDeclarativeListProperty<QObject> flickableData READ flickableData)
+ Q_PROPERTY(QDeclarativeListProperty<QSGItem> flickableChildren READ flickableChildren)
+ Q_CLASSINFO("DefaultProperty", "flickableData")
+
+ Q_ENUMS(FlickableDirection)
+ Q_ENUMS(BoundsBehavior)
+
+public:
+ QSGFlickable(QSGItem *parent=0);
+ ~QSGFlickable();
+
+ QDeclarativeListProperty<QObject> flickableData();
+ QDeclarativeListProperty<QSGItem> flickableChildren();
+
+ enum BoundsBehavior { StopAtBounds, DragOverBounds, DragAndOvershootBounds };
+ BoundsBehavior boundsBehavior() const;
+ void setBoundsBehavior(BoundsBehavior);
+
+ qreal contentWidth() const;
+ void setContentWidth(qreal);
+
+ qreal contentHeight() const;
+ void setContentHeight(qreal);
+
+ qreal contentX() const;
+ virtual void setContentX(qreal pos);
+
+ qreal contentY() const;
+ virtual void setContentY(qreal pos);
+
+ bool isMoving() const;
+ bool isMovingHorizontally() const;
+ bool isMovingVertically() const;
+ bool isFlicking() const;
+ bool isFlickingHorizontally() const;
+ bool isFlickingVertically() const;
+
+ int pressDelay() const;
+ void setPressDelay(int delay);
+
+ qreal maximumFlickVelocity() const;
+ void setMaximumFlickVelocity(qreal);
+
+ qreal flickDeceleration() const;
+ void setFlickDeceleration(qreal);
+
+ bool isInteractive() const;
+ void setInteractive(bool);
+
+ qreal horizontalVelocity() const;
+ qreal verticalVelocity() const;
+
+ bool isAtXEnd() const;
+ bool isAtXBeginning() const;
+ bool isAtYEnd() const;
+ bool isAtYBeginning() const;
+
+ QSGItem *contentItem();
+
+ enum FlickableDirection { AutoFlickDirection=0x00, HorizontalFlick=0x01, VerticalFlick=0x02, HorizontalAndVerticalFlick=0x03 };
+ FlickableDirection flickableDirection() const;
+ void setFlickableDirection(FlickableDirection);
+
+ Q_INVOKABLE void resizeContent(qreal w, qreal h, QPointF center);
+ Q_INVOKABLE void returnToBounds();
+
+Q_SIGNALS:
+ void contentWidthChanged();
+ void contentHeightChanged();
+ void contentXChanged();
+ void contentYChanged();
+ void movingChanged();
+ void movingHorizontallyChanged();
+ void movingVerticallyChanged();
+ void flickingChanged();
+ void flickingHorizontallyChanged();
+ void flickingVerticallyChanged();
+ void horizontalVelocityChanged();
+ void verticalVelocityChanged();
+ void isAtBoundaryChanged();
+ void flickableDirectionChanged();
+ void interactiveChanged();
+ void boundsBehaviorChanged();
+ void maximumFlickVelocityChanged();
+ void flickDecelerationChanged();
+ void pressDelayChanged();
+ void movementStarted();
+ void movementEnded();
+ void flickStarted();
+ void flickEnded();
+
+protected:
+ virtual bool childMouseEventFilter(QSGItem *, QEvent *);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void wheelEvent(QGraphicsSceneWheelEvent *event);
+ virtual void timerEvent(QTimerEvent *event);
+
+ QSGFlickableVisibleArea *visibleArea();
+
+protected Q_SLOTS:
+ virtual void ticked();
+ void movementStarting();
+ void movementEnding();
+
+protected:
+ void movementXEnding();
+ void movementYEnding();
+ virtual qreal minXExtent() const;
+ virtual qreal minYExtent() const;
+ virtual qreal maxXExtent() const;
+ virtual qreal maxYExtent() const;
+ qreal vWidth() const;
+ qreal vHeight() const;
+ virtual void viewportMoved();
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ void mouseUngrabEvent();
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+
+ bool xflick() const;
+ bool yflick() const;
+ void cancelFlick();
+
+protected:
+ QSGFlickable(QSGFlickablePrivate &dd, QSGItem *parent);
+
+private:
+ Q_DISABLE_COPY(QSGFlickable)
+ Q_DECLARE_PRIVATE(QSGFlickable)
+ friend class QSGFlickableVisibleArea;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGFlickable)
+
+QT_END_HEADER
+
+#endif // QSGFLICKABLE_P_H
diff --git a/src/declarative/items/qsgflickable_p_p.h b/src/declarative/items/qsgflickable_p_p.h
new file mode 100644
index 0000000000..2861bfd5b3
--- /dev/null
+++ b/src/declarative/items/qsgflickable_p_p.h
@@ -0,0 +1,231 @@
+// Commit: cb0a6844705802564c81b581f24a76c5d5adf6d1
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFLICKABLE_P_P_H
+#define QSGFLICKABLE_P_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 "qsgflickable_p.h"
+#include "qsgitem_p.h"
+#include "qsgitemchangelistener_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtCore/qdatetime.h>
+
+#include <private/qdeclarativetimeline_p_p.h>
+#include <private/qdeclarativeanimation_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// Really slow flicks can be annoying.
+const qreal MinimumFlickVelocity = 75.0;
+
+class QSGFlickableVisibleArea;
+class QSGFlickablePrivate : public QSGItemPrivate, public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGFlickable)
+
+public:
+ static inline QSGFlickablePrivate *get(QSGFlickable *o) { return o->d_func(); }
+
+ QSGFlickablePrivate();
+ void init();
+
+ struct Velocity : public QDeclarativeTimeLineValue
+ {
+ Velocity(QSGFlickablePrivate *p)
+ : parent(p) {}
+ virtual void setValue(qreal v) {
+ if (v != value()) {
+ QDeclarativeTimeLineValue::setValue(v);
+ parent->updateVelocity();
+ }
+ }
+ QSGFlickablePrivate *parent;
+ };
+
+ struct AxisData {
+ AxisData(QSGFlickablePrivate *fp, void (QSGFlickablePrivate::*func)(qreal))
+ : move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true)
+ , fixingUp(false)
+ {}
+
+ QDeclarativeTimeLineValueProxy<QSGFlickablePrivate> move;
+ qreal viewSize;
+ qreal pressPos;
+ qreal dragStartOffset;
+ qreal dragMinBound;
+ qreal dragMaxBound;
+ qreal velocity;
+ qreal flickTarget;
+ QSGFlickablePrivate::Velocity smoothVelocity;
+ bool atEnd : 1;
+ bool atBeginning : 1;
+ bool fixingUp : 1;
+ };
+
+ void flickX(qreal velocity);
+ void flickY(qreal velocity);
+ virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
+
+ void fixupX();
+ void fixupY();
+ virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
+
+ void updateBeginningEnd();
+
+ bool isOutermostPressDelay() const;
+ void captureDelayedPress(QGraphicsSceneMouseEvent *event);
+ void clearDelayedPress();
+
+ void setRoundedViewportX(qreal x);
+ void setRoundedViewportY(qreal y);
+
+ qreal overShootDistance(qreal velocity, qreal size);
+
+ void itemGeometryChanged(QSGItem *, const QRectF &, const QRectF &);
+
+public:
+ QSGItem *contentItem;
+
+ AxisData hData;
+ AxisData vData;
+
+ QDeclarativeTimeLine timeline;
+ bool flickingHorizontally : 1;
+ bool flickingVertically : 1;
+ bool hMoved : 1;
+ bool vMoved : 1;
+ bool movingHorizontally : 1;
+ bool movingVertically : 1;
+ bool stealMouse : 1;
+ bool pressed : 1;
+ bool interactive : 1;
+ bool calcVelocity : 1;
+ QElapsedTimer lastPosTime;
+ QPointF lastPos;
+ QPointF pressPos;
+ QElapsedTimer pressTime;
+ qreal deceleration;
+ qreal maxVelocity;
+ QElapsedTimer velocityTime;
+ QPointF lastFlickablePosition;
+ qreal reportedVelocitySmoothing;
+ QGraphicsSceneMouseEvent *delayedPressEvent;
+ QSGItem *delayedPressTarget;
+ QBasicTimer delayedPressTimer;
+ int pressDelay;
+ int fixupDuration;
+
+ enum FixupMode { Normal, Immediate, ExtentChanged };
+ FixupMode fixupMode;
+
+ static void fixupY_callback(void *);
+ static void fixupX_callback(void *);
+
+ void updateVelocity();
+ int vTime;
+ QDeclarativeTimeLine velocityTimeline;
+ QSGFlickableVisibleArea *visibleArea;
+ QSGFlickable::FlickableDirection flickableDirection;
+ QSGFlickable::BoundsBehavior boundsBehavior;
+
+ void handleMousePressEvent(QGraphicsSceneMouseEvent *);
+ void handleMouseMoveEvent(QGraphicsSceneMouseEvent *);
+ void handleMouseReleaseEvent(QGraphicsSceneMouseEvent *);
+
+ // flickableData property
+ static void data_append(QDeclarativeListProperty<QObject> *, QObject *);
+ static int data_count(QDeclarativeListProperty<QObject> *);
+ static QObject *data_at(QDeclarativeListProperty<QObject> *, int);
+ static void data_clear(QDeclarativeListProperty<QObject> *);
+};
+
+class QSGFlickableVisibleArea : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal xPosition READ xPosition NOTIFY xPositionChanged)
+ Q_PROPERTY(qreal yPosition READ yPosition NOTIFY yPositionChanged)
+ Q_PROPERTY(qreal widthRatio READ widthRatio NOTIFY widthRatioChanged)
+ Q_PROPERTY(qreal heightRatio READ heightRatio NOTIFY heightRatioChanged)
+
+public:
+ QSGFlickableVisibleArea(QSGFlickable *parent=0);
+
+ qreal xPosition() const;
+ qreal widthRatio() const;
+ qreal yPosition() const;
+ qreal heightRatio() const;
+
+ void updateVisible();
+
+signals:
+ void xPositionChanged(qreal xPosition);
+ void yPositionChanged(qreal yPosition);
+ void widthRatioChanged(qreal widthRatio);
+ void heightRatioChanged(qreal heightRatio);
+
+private:
+ QSGFlickable *flickable;
+ qreal m_xPosition;
+ qreal m_widthRatio;
+ qreal m_yPosition;
+ qreal m_heightRatio;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGFlickableVisibleArea)
+
+#endif // QSGFLICKABLE_P_P_H
diff --git a/src/declarative/items/qsgflipable.cpp b/src/declarative/items/qsgflipable.cpp
new file mode 100644
index 0000000000..a856d6360b
--- /dev/null
+++ b/src/declarative/items/qsgflipable.cpp
@@ -0,0 +1,255 @@
+// Commit: caee66da925949cf7aef2ff8e1a86c38dd6e6efd
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgflipable_p.h"
+#include "qsgitem_p.h"
+
+#include <private/qdeclarativeguard_p.h>
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+// XXX todo - i think this needs work and a bit of a re-think
+
+class QSGLocalTransform : public QSGTransform
+{
+ Q_OBJECT
+public:
+ QSGLocalTransform(QObject *parent) : QSGTransform(parent) {}
+
+ void setTransform(const QTransform &t) {
+ transform = t;
+ update();
+ }
+ virtual void applyTo(QMatrix4x4 *matrix) const {
+ *matrix *= transform;
+ }
+private:
+ QTransform transform;
+};
+
+class QSGFlipablePrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGFlipable)
+public:
+ QSGFlipablePrivate() : current(QSGFlipable::Front), front(0), back(0), sideDirty(false) {}
+
+ virtual void transformChanged();
+ void updateSide();
+ void setBackTransform();
+
+ QSGFlipable::Side current;
+ QDeclarativeGuard<QSGLocalTransform> backTransform;
+ QDeclarativeGuard<QSGItem> front;
+ QDeclarativeGuard<QSGItem> back;
+
+ bool sideDirty;
+ bool wantBackXFlipped;
+ bool wantBackYFlipped;
+};
+
+QSGFlipable::QSGFlipable(QSGItem *parent)
+: QSGItem(*(new QSGFlipablePrivate), parent)
+{
+}
+
+QSGFlipable::~QSGFlipable()
+{
+}
+
+QSGItem *QSGFlipable::front()
+{
+ Q_D(const QSGFlipable);
+ return d->front;
+}
+
+void QSGFlipable::setFront(QSGItem *front)
+{
+ Q_D(QSGFlipable);
+ if (d->front) {
+ qmlInfo(this) << tr("front is a write-once property");
+ return;
+ }
+ d->front = front;
+ d->front->setParentItem(this);
+ if (Back == d->current)
+ d->front->setOpacity(0.);
+ emit frontChanged();
+}
+
+QSGItem *QSGFlipable::back()
+{
+ Q_D(const QSGFlipable);
+ return d->back;
+}
+
+void QSGFlipable::setBack(QSGItem *back)
+{
+ Q_D(QSGFlipable);
+ if (d->back) {
+ qmlInfo(this) << tr("back is a write-once property");
+ return;
+ }
+ if (back == 0)
+ return;
+ d->back = back;
+ d->back->setParentItem(this);
+
+ d->backTransform = new QSGLocalTransform(d->back);
+ d->backTransform->prependToItem(d->back);
+
+ if (Front == d->current)
+ d->back->setOpacity(0.);
+ connect(back, SIGNAL(widthChanged()),
+ this, SLOT(retransformBack()));
+ connect(back, SIGNAL(heightChanged()),
+ this, SLOT(retransformBack()));
+ emit backChanged();
+}
+
+void QSGFlipable::retransformBack()
+{
+ Q_D(QSGFlipable);
+ if (d->current == QSGFlipable::Back && d->back)
+ d->setBackTransform();
+}
+
+QSGFlipable::Side QSGFlipable::side() const
+{
+ Q_D(const QSGFlipable);
+
+ const_cast<QSGFlipablePrivate *>(d)->updateSide();
+ return d->current;
+}
+
+void QSGFlipablePrivate::transformChanged()
+{
+ Q_Q(QSGFlipable);
+
+ if (!sideDirty) {
+ sideDirty = true;
+ q->polish();
+ }
+
+ QSGItemPrivate::transformChanged();
+}
+
+void QSGFlipable::updatePolish()
+{
+ Q_D(QSGFlipable);
+ d->updateSide();
+}
+
+// determination on the currently visible side of the flipable
+// has to be done on the complete scene transform to give
+// correct results.
+void QSGFlipablePrivate::updateSide()
+{
+ Q_Q(QSGFlipable);
+
+ if (!sideDirty)
+ return;
+
+ sideDirty = false;
+
+ QTransform sceneTransform;
+ itemToParentTransform(sceneTransform);
+
+ QPointF p1(0, 0);
+ QPointF p2(1, 0);
+ QPointF p3(1, 1);
+
+ QPointF scenep1 = sceneTransform.map(p1);
+ QPointF scenep2 = sceneTransform.map(p2);
+ QPointF scenep3 = sceneTransform.map(p3);
+#if 0
+ p1 = q->mapToParent(p1);
+ p2 = q->mapToParent(p2);
+ p3 = q->mapToParent(p3);
+#endif
+
+ qreal cross = (scenep1.x() - scenep2.x()) * (scenep3.y() - scenep2.y()) -
+ (scenep1.y() - scenep2.y()) * (scenep3.x() - scenep2.x());
+
+ wantBackYFlipped = scenep1.x() >= scenep2.x();
+ wantBackXFlipped = scenep2.y() >= scenep3.y();
+
+ QSGFlipable::Side newSide;
+ if (cross > 0) {
+ newSide = QSGFlipable::Back;
+ } else {
+ newSide = QSGFlipable::Front;
+ }
+
+ if (newSide != current) {
+ current = newSide;
+ if (current == QSGFlipable::Back && back)
+ setBackTransform();
+ if (front)
+ front->setOpacity((current==QSGFlipable::Front)?1.:0.);
+ if (back)
+ back->setOpacity((current==QSGFlipable::Back)?1.:0.);
+ emit q->sideChanged();
+ }
+}
+
+/* Depends on the width/height of the back item, and so needs reevaulating
+ if those change.
+*/
+void QSGFlipablePrivate::setBackTransform()
+{
+ QTransform mat;
+ mat.translate(back->width()/2,back->height()/2);
+ if (back->width() && wantBackYFlipped)
+ mat.rotate(180, Qt::YAxis);
+ if (back->height() && wantBackXFlipped)
+ mat.rotate(180, Qt::XAxis);
+ mat.translate(-back->width()/2,-back->height()/2);
+
+ if (backTransform)
+ backTransform->setTransform(mat);
+}
+
+QT_END_NAMESPACE
+
+#include "qsgflipable.moc"
diff --git a/src/declarative/items/qsgflipable_p.h b/src/declarative/items/qsgflipable_p.h
new file mode 100644
index 0000000000..02178adca8
--- /dev/null
+++ b/src/declarative/items/qsgflipable_p.h
@@ -0,0 +1,104 @@
+// Commit: ebd4bc73c46c2962742a682b6a391fb68c482aec
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFLIPABLE_P_H
+#define QSGFLIPABLE_P_H
+
+#include "qsgitem.h"
+
+#include <QtGui/qtransform.h>
+#include <QtGui/qvector3d.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGFlipablePrivate;
+class Q_AUTOTEST_EXPORT QSGFlipable : public QSGItem
+{
+ Q_OBJECT
+
+ Q_ENUMS(Side)
+ Q_PROPERTY(QSGItem *front READ front WRITE setFront NOTIFY frontChanged)
+ Q_PROPERTY(QSGItem *back READ back WRITE setBack NOTIFY backChanged)
+ Q_PROPERTY(Side side READ side NOTIFY sideChanged)
+ //### flipAxis
+ //### flipRotation
+public:
+ QSGFlipable(QSGItem *parent=0);
+ ~QSGFlipable();
+
+ QSGItem *front();
+ void setFront(QSGItem *);
+
+ QSGItem *back();
+ void setBack(QSGItem *);
+
+ enum Side { Front, Back };
+ Side side() const;
+
+Q_SIGNALS:
+ void frontChanged();
+ void backChanged();
+ void sideChanged();
+
+protected:
+ virtual void updatePolish();
+
+private Q_SLOTS:
+ void retransformBack();
+
+private:
+ Q_DISABLE_COPY(QSGFlipable)
+ Q_DECLARE_PRIVATE(QSGFlipable)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGFlipable)
+
+QT_END_HEADER
+
+#endif // QSGFLIPABLE_P_H
diff --git a/src/declarative/items/qsgfocusscope.cpp b/src/declarative/items/qsgfocusscope.cpp
new file mode 100644
index 0000000000..84f19b1671
--- /dev/null
+++ b/src/declarative/items/qsgfocusscope.cpp
@@ -0,0 +1,57 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgfocusscope_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGFocusScope::QSGFocusScope(QSGItem *parent)
+: QSGItem(parent)
+{
+ setFlag(ItemIsFocusScope);
+}
+
+QSGFocusScope::~QSGFocusScope()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgfocusscope_p.h b/src/declarative/items/qsgfocusscope_p.h
new file mode 100644
index 0000000000..ceffd9f089
--- /dev/null
+++ b/src/declarative/items/qsgfocusscope_p.h
@@ -0,0 +1,68 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFOCUSSCOPE_P_H
+#define QSGFOCUSSCOPE_P_H
+
+#include "qsgitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QSGFocusScope : public QSGItem
+{
+ Q_OBJECT
+public:
+ QSGFocusScope(QSGItem *parent=0);
+ virtual ~QSGFocusScope();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGFocusScope)
+
+QT_END_HEADER
+
+#endif // QSGFOCUSSCOPE_P_H
diff --git a/src/declarative/items/qsggridview.cpp b/src/declarative/items/qsggridview.cpp
new file mode 100644
index 0000000000..9beac05d72
--- /dev/null
+++ b/src/declarative/items/qsggridview.cpp
@@ -0,0 +1,2634 @@
+// Commit: cc6408ccd5453d1bed9f98b9caa14861cea5742b
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsggridview_p.h"
+#include "qsgvisualitemmodel_p.h"
+#include "qsgflickable_p_p.h"
+
+#include <private/qdeclarativesmoothedanimation_p_p.h>
+#include <private/qlistmodelinterface_p.h>
+
+#include <QtGui/qevent.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qcoreapplication.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+//----------------------------------------------------------------------------
+
+class FxGridItemSG
+{
+public:
+ FxGridItemSG(QSGItem *i, QSGGridView *v) : item(i), view(v) {
+ attached = static_cast<QSGGridViewAttached*>(qmlAttachedPropertiesObject<QSGGridView>(item));
+ if (attached)
+ attached->setView(view);
+ }
+ ~FxGridItemSG() {}
+
+ qreal rowPos() const {
+ qreal rowPos = 0;
+ if (view->flow() == QSGGridView::LeftToRight) {
+ rowPos = item->y();
+ } else {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft)
+ rowPos = -view->cellWidth()-item->x();
+ else
+ rowPos = item->x();
+ }
+ return rowPos;
+ }
+ qreal colPos() const {
+ qreal colPos = 0;
+ if (view->flow() == QSGGridView::LeftToRight) {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
+ int colSize = view->cellWidth();
+ int columns = view->width()/colSize;
+ colPos = colSize * (columns-1) - item->x();
+ } else {
+ colPos = item->x();
+ }
+ } else {
+ colPos = item->y();
+ }
+
+ return colPos;
+ }
+ qreal endRowPos() const {
+ if (view->flow() == QSGGridView::LeftToRight) {
+ return item->y() + view->cellHeight() - 1;
+ } else {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft)
+ return -item->x() - 1;
+ else
+ return item->x() + view->cellWidth() - 1;
+ }
+ }
+ void setPosition(qreal col, qreal row) {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
+ if (view->flow() == QSGGridView::LeftToRight) {
+ int columns = view->width()/view->cellWidth();
+ item->setPos(QPointF((view->cellWidth() * (columns-1) - col), row));
+ } else {
+ item->setPos(QPointF(-view->cellWidth()-row, col));
+ }
+ } else {
+ if (view->flow() == QSGGridView::LeftToRight)
+ item->setPos(QPointF(col, row));
+ else
+ item->setPos(QPointF(row, col));
+ }
+ }
+ bool contains(qreal x, qreal y) const {
+ return (x >= item->x() && x < item->x() + view->cellWidth() &&
+ y >= item->y() && y < item->y() + view->cellHeight());
+ }
+
+ QSGItem *item;
+ QSGGridView *view;
+ QSGGridViewAttached *attached;
+ int index;
+};
+
+//----------------------------------------------------------------------------
+
+class QSGGridViewPrivate : public QSGFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QSGGridView)
+
+public:
+ QSGGridViewPrivate()
+ : currentItem(0), layoutDirection(Qt::LeftToRight), flow(QSGGridView::LeftToRight)
+ , visibleIndex(0) , currentIndex(-1)
+ , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0)
+ , highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightRange(QSGGridView::NoHighlightRange)
+ , highlightComponent(0), highlight(0), trackedItem(0)
+ , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0)
+ , highlightMoveDuration(150)
+ , footerComponent(0), footer(0), headerComponent(0), header(0)
+ , bufferMode(BufferBefore | BufferAfter), snapMode(QSGGridView::NoSnap)
+ , ownModel(false), wrap(false), autoHighlight(true)
+ , fixCurrentVisibility(false), lazyRelease(false), layoutScheduled(false)
+ , deferredRelease(false), haveHighlightRange(false), currentIndexCleared(false)
+ , highlightRangeStartValid(false), highlightRangeEndValid(false) {}
+
+ void init();
+ void clear();
+ FxGridItemSG *createItem(int modelIndex);
+ void releaseItem(FxGridItemSG *item);
+ void refill(qreal from, qreal to, bool doBuffer=false);
+
+ void updateGrid();
+ void scheduleLayout();
+ void layout();
+ void updateUnrequestedIndexes();
+ void updateUnrequestedPositions();
+ void updateTrackedItem();
+ void createHighlight();
+ void updateHighlight();
+ void updateCurrent(int modelIndex);
+ void updateHeader();
+ void updateFooter();
+ void fixupPosition();
+
+ FxGridItemSG *visibleItem(int modelIndex) const {
+ if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
+ for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems.at(i);
+ if (item->index == modelIndex)
+ return item;
+ }
+ }
+ return 0;
+ }
+
+ bool isRightToLeftTopToBottom() const {
+ Q_Q(const QSGGridView);
+ return flow == QSGGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
+ }
+
+ void regenerate() {
+ Q_Q(QSGGridView);
+ if (q->isComponentComplete()) {
+ clear();
+ updateGrid();
+ setPosition(0);
+ q->refill();
+ updateCurrent(currentIndex);
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QSGGridView);
+ regenerate();
+ emit q->effectiveLayoutDirectionChanged();
+ }
+
+ qreal position() const {
+ Q_Q(const QSGGridView);
+ return flow == QSGGridView::LeftToRight ? q->contentY() : q->contentX();
+ }
+ void setPosition(qreal pos) {
+ Q_Q(QSGGridView);
+ if (flow == QSGGridView::LeftToRight) {
+ q->QSGFlickable::setContentY(pos);
+ q->QSGFlickable::setContentX(0);
+ } else {
+ if (q->effectiveLayoutDirection() == Qt::LeftToRight)
+ q->QSGFlickable::setContentX(pos);
+ else
+ q->QSGFlickable::setContentX(-pos-size());
+ q->QSGFlickable::setContentY(0);
+ }
+ }
+ int size() const {
+ Q_Q(const QSGGridView);
+ return flow == QSGGridView::LeftToRight ? q->height() : q->width();
+ }
+ qreal originPosition() const {
+ qreal pos = 0;
+ if (!visibleItems.isEmpty())
+ pos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
+ return pos;
+ }
+
+ qreal lastPosition() const {
+ qreal pos = 0;
+ if (model && model->count())
+ pos = rowPosAt(model->count() - 1) + rowSize();
+ return pos;
+ }
+
+ qreal startPosition() const {
+ return isRightToLeftTopToBottom() ? -lastPosition()+1 : originPosition();
+ }
+
+ qreal endPosition() const {
+ return isRightToLeftTopToBottom() ? -originPosition()+1 : lastPosition();
+
+ }
+
+ bool isValid() const {
+ return model && model->count() && model->isValid();
+ }
+
+ int rowSize() const {
+ return flow == QSGGridView::LeftToRight ? cellHeight : cellWidth;
+ }
+ int colSize() const {
+ return flow == QSGGridView::LeftToRight ? cellWidth : cellHeight;
+ }
+
+ qreal colPosAt(int modelIndex) const {
+ if (FxGridItemSG *item = visibleItem(modelIndex))
+ return item->colPos();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int count = (visibleIndex - modelIndex) % columns;
+ int col = visibleItems.first()->colPos() / colSize();
+ col = (columns - count + col) % columns;
+ return col * colSize();
+ } else {
+ int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns;
+ return visibleItems.last()->colPos() - count * colSize();
+ }
+ } else {
+ return (modelIndex % columns) * colSize();
+ }
+ return 0;
+ }
+ qreal rowPosAt(int modelIndex) const {
+ if (FxGridItemSG *item = visibleItem(modelIndex))
+ return item->rowPos();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int firstCol = visibleItems.first()->colPos() / colSize();
+ int col = visibleIndex - modelIndex + (columns - firstCol - 1);
+ int rows = col / columns;
+ return visibleItems.first()->rowPos() - rows * rowSize();
+ } else {
+ int count = modelIndex - visibleItems.last()->index;
+ int col = visibleItems.last()->colPos() + count * colSize();
+ int rows = col / (columns * colSize());
+ return visibleItems.last()->rowPos() + rows * rowSize();
+ }
+ } else {
+ qreal pos = (modelIndex / columns) * rowSize();
+ if (header)
+ pos += headerSize();
+ return pos;
+ }
+ return 0;
+ }
+
+ FxGridItemSG *firstVisibleItem() const {
+ const qreal pos = isRightToLeftTopToBottom() ? -position()-size() : position();
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems.at(i);
+ if (item->index != -1 && item->endRowPos() > pos)
+ return item;
+ }
+ return visibleItems.count() ? visibleItems.first() : 0;
+ }
+
+ int lastVisibleIndex() const {
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems.at(i);
+ if (item->index != -1)
+ return item->index;
+ }
+ return -1;
+ }
+
+ // Map a model index to visibleItems list index.
+ // These may differ if removed items are still present in the visible list,
+ // e.g. doing a removal animation
+ int mapFromModel(int modelIndex) const {
+ if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
+ return -1;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *listItem = visibleItems.at(i);
+ if (listItem->index == modelIndex)
+ return i + visibleIndex;
+ if (listItem->index > modelIndex)
+ return -1;
+ }
+ return -1; // Not in visibleList
+ }
+
+ qreal snapPosAt(qreal pos) const {
+ Q_Q(const QSGGridView);
+ qreal snapPos = 0;
+ if (!visibleItems.isEmpty()) {
+ pos += rowSize()/2;
+ snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
+ snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
+ qreal maxExtent;
+ qreal minExtent;
+ if (isRightToLeftTopToBottom()) {
+ maxExtent = q->minXExtent();
+ minExtent = q->maxXExtent();
+ } else {
+ maxExtent = flow == QSGGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
+ minExtent = flow == QSGGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
+ }
+ if (snapPos > maxExtent)
+ snapPos = maxExtent;
+ if (snapPos < minExtent)
+ snapPos = minExtent;
+ }
+ return snapPos;
+ }
+
+ FxGridItemSG *snapItemAt(qreal pos) {
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems[i];
+ if (item->index == -1)
+ continue;
+ qreal itemTop = item->rowPos();
+ if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
+ return item;
+ }
+ return 0;
+ }
+
+ int snapIndex() {
+ int index = currentIndex;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems[i];
+ if (item->index == -1)
+ continue;
+ qreal itemTop = item->rowPos();
+ if (itemTop >= highlight->rowPos()-rowSize()/2 && itemTop < highlight->rowPos()+rowSize()/2) {
+ index = item->index;
+ if (item->colPos() >= highlight->colPos()-colSize()/2 && item->colPos() < highlight->colPos()+colSize()/2)
+ return item->index;
+ }
+ }
+ return index;
+ }
+
+ qreal headerSize() const {
+ if (!header)
+ return 0.0;
+
+ return flow == QSGGridView::LeftToRight
+ ? header->item->height()
+ : header->item->width();
+ }
+
+
+ virtual void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
+ Q_Q(const QSGGridView);
+ QSGFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
+ if (item == q) {
+ if (newGeometry.height() != oldGeometry.height()
+ || newGeometry.width() != oldGeometry.width()) {
+ if (q->isComponentComplete()) {
+ updateGrid();
+ scheduleLayout();
+ }
+ }
+ } else if ((header && header->item == item) || (footer && footer->item == item)) {
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ }
+ }
+
+ void positionViewAtIndex(int index, int mode);
+ virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
+ virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
+
+ // for debugging only
+ void checkVisible() const {
+ int skip = 0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItemSG *listItem = visibleItems.at(i);
+ if (listItem->index == -1) {
+ ++skip;
+ } else if (listItem->index != visibleIndex + i - skip) {
+ for (int j = 0; j < visibleItems.count(); j++)
+ qDebug() << " index" << j << "item index" << visibleItems.at(j)->index;
+ qFatal("index %d %d %d", visibleIndex, i, listItem->index);
+ }
+ }
+ }
+
+ QDeclarativeGuard<QSGVisualModel> model;
+ QVariant modelVariant;
+ QList<FxGridItemSG*> visibleItems;
+ QHash<QSGItem*,int> unrequestedItems;
+ FxGridItemSG *currentItem;
+ Qt::LayoutDirection layoutDirection;
+ QSGGridView::Flow flow;
+ int visibleIndex;
+ int currentIndex;
+ int cellWidth;
+ int cellHeight;
+ int columns;
+ int requestedIndex;
+ int itemCount;
+ qreal highlightRangeStart;
+ qreal highlightRangeEnd;
+ QSGGridView::HighlightRangeMode highlightRange;
+ QDeclarativeComponent *highlightComponent;
+ FxGridItemSG *highlight;
+ FxGridItemSG *trackedItem;
+ enum MovementReason { Other, SetIndex, Mouse };
+ MovementReason moveReason;
+ int buffer;
+ QSmoothedAnimation *highlightXAnimator;
+ QSmoothedAnimation *highlightYAnimator;
+ int highlightMoveDuration;
+ QDeclarativeComponent *footerComponent;
+ FxGridItemSG *footer;
+ QDeclarativeComponent *headerComponent;
+ FxGridItemSG *header;
+ enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
+ int bufferMode;
+ QSGGridView::SnapMode snapMode;
+
+ bool ownModel : 1;
+ bool wrap : 1;
+ bool autoHighlight : 1;
+ bool fixCurrentVisibility : 1;
+ bool lazyRelease : 1;
+ bool layoutScheduled : 1;
+ bool deferredRelease : 1;
+ bool haveHighlightRange : 1;
+ bool currentIndexCleared : 1;
+ bool highlightRangeStartValid : 1;
+ bool highlightRangeEndValid : 1;
+};
+
+void QSGGridViewPrivate::init()
+{
+ Q_Q(QSGGridView);
+ QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
+ q->setFlag(QSGItem::ItemIsFocusScope);
+ q->setFlickableDirection(QSGFlickable::VerticalFlick);
+ addItemChangeListener(this, Geometry);
+}
+
+void QSGGridViewPrivate::clear()
+{
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ visibleIndex = 0;
+ releaseItem(currentItem);
+ currentItem = 0;
+ createHighlight();
+ trackedItem = 0;
+ itemCount = 0;
+}
+
+FxGridItemSG *QSGGridViewPrivate::createItem(int modelIndex)
+{
+ Q_Q(QSGGridView);
+ // create object
+ requestedIndex = modelIndex;
+ FxGridItemSG *listItem = 0;
+ if (QSGItem *item = model->item(modelIndex, false)) {
+ listItem = new FxGridItemSG(item, q);
+ listItem->index = modelIndex;
+ if (model->completePending()) {
+ // complete
+ listItem->item->setZ(1);
+ listItem->item->setParentItem(q->contentItem());
+ model->completeItem();
+ } else {
+ listItem->item->setParentItem(q->contentItem());
+ }
+ unrequestedItems.remove(listItem->item);
+ }
+ requestedIndex = -1;
+ return listItem;
+}
+
+
+void QSGGridViewPrivate::releaseItem(FxGridItemSG *item)
+{
+ Q_Q(QSGGridView);
+ if (!item || !model)
+ return;
+ if (trackedItem == item) {
+ QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
+ QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
+ trackedItem = 0;
+ }
+ if (model->release(item->item) == 0) {
+ // item was not destroyed, and we no longer reference it.
+ unrequestedItems.insert(item->item, model->indexOf(item->item, q));
+ }
+ delete item;
+}
+
+void QSGGridViewPrivate::refill(qreal from, qreal to, bool doBuffer)
+{
+ Q_Q(QSGGridView);
+ if (!isValid() || !q->isComponentComplete())
+ return;
+ itemCount = model->count();
+ qreal bufferFrom = from - buffer;
+ qreal bufferTo = to + buffer;
+ qreal fillFrom = from;
+ qreal fillTo = to;
+ if (doBuffer && (bufferMode & BufferAfter))
+ fillTo = bufferTo;
+ if (doBuffer && (bufferMode & BufferBefore))
+ fillFrom = bufferFrom;
+
+ bool changed = false;
+
+ int colPos = colPosAt(visibleIndex);
+ int rowPos = rowPosAt(visibleIndex);
+ int modelIndex = visibleIndex;
+ if (visibleItems.count()) {
+ rowPos = visibleItems.last()->rowPos();
+ colPos = visibleItems.last()->colPos() + colSize();
+ if (colPos > colSize() * (columns-1)) {
+ colPos = 0;
+ rowPos += rowSize();
+ }
+ int i = visibleItems.count() - 1;
+ while (i > 0 && visibleItems.at(i)->index == -1)
+ --i;
+ modelIndex = visibleItems.at(i)->index + 1;
+ }
+ int colNum = colPos / colSize();
+
+ FxGridItemSG *item = 0;
+
+ // Item creation and release is staggered in order to avoid
+ // creating/releasing multiple items in one frame
+ // while flicking (as much as possible).
+ while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
+// qDebug() << "refill: append item" << modelIndex;
+ if (!(item = createItem(modelIndex)))
+ break;
+ item->setPosition(colPos, rowPos);
+ visibleItems.append(item);
+ colPos += colSize();
+ colNum++;
+ if (colPos > colSize() * (columns-1)) {
+ colPos = 0;
+ colNum = 0;
+ rowPos += rowSize();
+ }
+ ++modelIndex;
+ changed = true;
+ if (doBuffer) // never buffer more than one item per frame
+ break;
+ }
+
+ if (visibleItems.count()) {
+ rowPos = visibleItems.first()->rowPos();
+ colPos = visibleItems.first()->colPos() - colSize();
+ if (colPos < 0) {
+ colPos = colSize() * (columns - 1);
+ rowPos -= rowSize();
+ }
+ }
+ colNum = colPos / colSize();
+ while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
+// qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
+ if (!(item = createItem(visibleIndex-1)))
+ break;
+ --visibleIndex;
+ item->setPosition(colPos, rowPos);
+ visibleItems.prepend(item);
+ colPos -= colSize();
+ colNum--;
+ if (colPos < 0) {
+ colPos = colSize() * (columns - 1);
+ colNum = columns-1;
+ rowPos -= rowSize();
+ }
+ changed = true;
+ if (doBuffer) // never buffer more than one item per frame
+ break;
+ }
+
+ if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
+ while (visibleItems.count() > 1
+ && (item = visibleItems.first())
+ && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
+ if (item->attached->delayRemove())
+ break;
+// qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
+ if (item->index != -1)
+ visibleIndex++;
+ visibleItems.removeFirst();
+ releaseItem(item);
+ changed = true;
+ }
+ while (visibleItems.count() > 1
+ && (item = visibleItems.last())
+ && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
+ if (item->attached->delayRemove())
+ break;
+// qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
+ visibleItems.removeLast();
+ releaseItem(item);
+ changed = true;
+ }
+ deferredRelease = false;
+ } else {
+ deferredRelease = true;
+ }
+ if (changed) {
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ if (flow == QSGGridView::LeftToRight)
+ q->setContentHeight(endPosition() - startPosition());
+ else
+ q->setContentWidth(endPosition() - startPosition());
+ } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
+ refill(from, to, true);
+ }
+ lazyRelease = false;
+}
+
+void QSGGridViewPrivate::updateGrid()
+{
+ Q_Q(QSGGridView);
+ columns = (int)qMax((flow == QSGGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
+ if (isValid()) {
+ if (flow == QSGGridView::LeftToRight)
+ q->setContentHeight(endPosition() - startPosition());
+ else
+ q->setContentWidth(lastPosition() - originPosition());
+ }
+}
+
+void QSGGridViewPrivate::scheduleLayout()
+{
+ Q_Q(QSGGridView);
+ if (!layoutScheduled) {
+ layoutScheduled = true;
+ q->polish();
+ }
+}
+
+void QSGGridViewPrivate::layout()
+{
+ Q_Q(QSGGridView);
+ layoutScheduled = false;
+ if (!isValid() && !visibleItems.count()) {
+ clear();
+ return;
+ }
+ if (visibleItems.count()) {
+ qreal rowPos = visibleItems.first()->rowPos();
+ qreal colPos = visibleItems.first()->colPos();
+ int col = visibleIndex % columns;
+ if (colPos != col * colSize()) {
+ colPos = col * colSize();
+ visibleItems.first()->setPosition(colPos, rowPos);
+ }
+ for (int i = 1; i < visibleItems.count(); ++i) {
+ FxGridItemSG *item = visibleItems.at(i);
+ colPos += colSize();
+ if (colPos > colSize() * (columns-1)) {
+ colPos = 0;
+ rowPos += rowSize();
+ }
+ item->setPosition(colPos, rowPos);
+ }
+ }
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ q->refill();
+ updateHighlight();
+ moveReason = Other;
+ if (flow == QSGGridView::LeftToRight) {
+ q->setContentHeight(endPosition() - startPosition());
+ fixupY();
+ } else {
+ q->setContentWidth(endPosition() - startPosition());
+ fixupX();
+ }
+ updateUnrequestedPositions();
+}
+
+void QSGGridViewPrivate::updateUnrequestedIndexes()
+{
+ Q_Q(QSGGridView);
+ QHash<QSGItem*,int>::iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
+ *it = model->indexOf(it.key(), q);
+}
+
+void QSGGridViewPrivate::updateUnrequestedPositions()
+{
+ QHash<QSGItem*,int>::const_iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
+ QSGItem *item = it.key();
+ if (flow == QSGGridView::LeftToRight) {
+ item->setPos(QPointF(colPosAt(*it), rowPosAt(*it)));
+ } else {
+ if (isRightToLeftTopToBottom())
+ item->setPos(QPointF(-rowPosAt(*it)-item->width(), colPosAt(*it)));
+ else
+ item->setPos(QPointF(rowPosAt(*it), colPosAt(*it)));
+ }
+ }
+}
+
+void QSGGridViewPrivate::updateTrackedItem()
+{
+ Q_Q(QSGGridView);
+ FxGridItemSG *item = currentItem;
+ if (highlight)
+ item = highlight;
+
+ if (trackedItem && item != trackedItem) {
+ QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
+ QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
+ trackedItem = 0;
+ }
+
+ if (!trackedItem && item) {
+ trackedItem = item;
+ QObject::connect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
+ QObject::connect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
+ }
+ if (trackedItem)
+ q->trackedPositionChanged();
+}
+
+void QSGGridViewPrivate::createHighlight()
+{
+ Q_Q(QSGGridView);
+ bool changed = false;
+ if (highlight) {
+ if (trackedItem == highlight)
+ trackedItem = 0;
+ delete highlight->item;
+ delete highlight;
+ highlight = 0;
+ delete highlightXAnimator;
+ delete highlightYAnimator;
+ highlightXAnimator = 0;
+ highlightYAnimator = 0;
+ changed = true;
+ }
+
+ if (currentItem) {
+ QSGItem *item = 0;
+ if (highlightComponent) {
+ QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = highlightComponent->create(highlightContext);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(highlightContext, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete highlightContext;
+ }
+ } else {
+ item = new QSGItem;
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ highlight = new FxGridItemSG(item, q);
+ if (currentItem && autoHighlight)
+ highlight->setPosition(currentItem->colPos(), currentItem->rowPos());
+ highlightXAnimator = new QSmoothedAnimation(q);
+ highlightXAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("x"));
+ highlightXAnimator->userDuration = highlightMoveDuration;
+ highlightYAnimator = new QSmoothedAnimation(q);
+ highlightYAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("y"));
+ highlightYAnimator->userDuration = highlightMoveDuration;
+ if (autoHighlight) {
+ highlightXAnimator->restart();
+ highlightYAnimator->restart();
+ }
+ changed = true;
+ }
+ }
+ if (changed)
+ emit q->highlightItemChanged();
+}
+
+void QSGGridViewPrivate::updateHighlight()
+{
+ if ((!currentItem && highlight) || (currentItem && !highlight))
+ createHighlight();
+ if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) {
+ // auto-update highlight
+ highlightXAnimator->to = currentItem->item->x();
+ highlightYAnimator->to = currentItem->item->y();
+ highlight->item->setWidth(currentItem->item->width());
+ highlight->item->setHeight(currentItem->item->height());
+ highlightXAnimator->restart();
+ highlightYAnimator->restart();
+ }
+ updateTrackedItem();
+}
+
+void QSGGridViewPrivate::updateCurrent(int modelIndex)
+{
+ Q_Q(QSGGridView);
+ if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
+ if (currentItem) {
+ currentItem->attached->setIsCurrentItem(false);
+ releaseItem(currentItem);
+ currentItem = 0;
+ currentIndex = modelIndex;
+ emit q->currentIndexChanged();
+ updateHighlight();
+ } else if (currentIndex != modelIndex) {
+ currentIndex = modelIndex;
+ emit q->currentIndexChanged();
+ }
+ return;
+ }
+
+ if (currentItem && currentIndex == modelIndex) {
+ updateHighlight();
+ return;
+ }
+
+ FxGridItemSG *oldCurrentItem = currentItem;
+ currentIndex = modelIndex;
+ currentItem = createItem(modelIndex);
+ fixCurrentVisibility = true;
+ if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
+ oldCurrentItem->attached->setIsCurrentItem(false);
+ if (currentItem) {
+ currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex));
+ currentItem->item->setFocus(true);
+ currentItem->attached->setIsCurrentItem(true);
+ }
+ updateHighlight();
+ emit q->currentIndexChanged();
+ releaseItem(oldCurrentItem);
+}
+
+void QSGGridViewPrivate::updateFooter()
+{
+ Q_Q(QSGGridView);
+ if (!footer && footerComponent) {
+ QSGItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = footerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZ(1);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ footer = new FxGridItemSG(item, q);
+ }
+ }
+ if (footer) {
+ qreal colOffset = 0;
+ qreal rowOffset;
+ if (isRightToLeftTopToBottom()) {
+ rowOffset = footer->item->width()-cellWidth;
+ } else {
+ rowOffset = 0;
+ if (q->effectiveLayoutDirection() == Qt::RightToLeft)
+ colOffset = footer->item->width()-cellWidth;
+ }
+ if (visibleItems.count()) {
+ qreal endPos = lastPosition();
+ if (lastVisibleIndex() == model->count()-1) {
+ footer->setPosition(colOffset, endPos + rowOffset);
+ } else {
+ qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size();
+ if (endPos <= visiblePos || footer->endRowPos() < endPos + rowOffset)
+ footer->setPosition(colOffset, endPos + rowOffset);
+ }
+ } else {
+ qreal endPos = 0;
+ if (header) {
+ endPos += (flow == QSGGridView::LeftToRight) ? header->item->height() : header->item->width();
+ }
+ footer->setPosition(colOffset, endPos);
+ }
+ }
+}
+
+void QSGGridViewPrivate::updateHeader()
+{
+ Q_Q(QSGGridView);
+ if (!header && headerComponent) {
+ QSGItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = headerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZ(1);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ header = new FxGridItemSG(item, q);
+ }
+ }
+ if (header) {
+ qreal colOffset = 0;
+ qreal rowOffset;
+ if (isRightToLeftTopToBottom()) {
+ rowOffset = -cellWidth;
+ } else {
+ rowOffset = -headerSize();
+ if (q->effectiveLayoutDirection() == Qt::RightToLeft)
+ colOffset = header->item->width()-cellWidth;
+ }
+ if (visibleItems.count()) {
+ qreal startPos = originPosition();
+ if (visibleIndex == 0) {
+ header->setPosition(colOffset, startPos + rowOffset);
+ } else {
+ qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position();
+ qreal headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
+ if (tempPos <= startPos || headerPos > startPos + rowOffset)
+ header->setPosition(colOffset, startPos + rowOffset);
+ }
+ } else {
+ header->setPosition(colOffset, 0);
+ }
+ }
+}
+
+void QSGGridViewPrivate::fixupPosition()
+{
+ moveReason = Other;
+ if (flow == QSGGridView::LeftToRight)
+ fixupY();
+ else
+ fixupX();
+}
+
+void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
+{
+ if ((flow == QSGGridView::TopToBottom && &data == &vData)
+ || (flow == QSGGridView::LeftToRight && &data == &hData))
+ return;
+
+ fixupMode = moveReason == Mouse ? fixupMode : Immediate;
+
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal viewPos;
+ if (isRightToLeftTopToBottom()) {
+ // Handle Right-To-Left exceptions
+ viewPos = -position()-size();
+ highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+ highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd;
+ } else {
+ viewPos = position();
+ highlightStart = highlightRangeStart;
+ highlightEnd = highlightRangeEnd;
+ }
+
+ if (snapMode != QSGGridView::NoSnap) {
+ qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
+ FxGridItemSG *topItem = snapItemAt(tempPosition+highlightStart);
+ FxGridItemSG *bottomItem = snapItemAt(tempPosition+highlightEnd);
+ qreal pos;
+ if (topItem && bottomItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
+ qreal topPos = qMin(topItem->rowPos() - highlightStart, -maxExtent);
+ qreal bottomPos = qMax(bottomItem->rowPos() - highlightEnd, -minExtent);
+ pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
+ } else if (topItem) {
+ qreal headerPos = 0;
+ if (header)
+ headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
+ if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2) {
+ pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart;
+ } else {
+ if (isRightToLeftTopToBottom())
+ pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent);
+ }
+ } else if (bottomItem) {
+ if (isRightToLeftTopToBottom())
+ pos = qMax(qMin(-bottomItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(bottomItem->rowPos() - highlightStart, -maxExtent), -minExtent);
+ } else {
+ QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
+ return;
+ }
+ if (currentItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
+ updateHighlight();
+ qreal currPos = currentItem->rowPos();
+ if (isRightToLeftTopToBottom())
+ pos = -pos-size(); // Transform Pos if required
+ if (pos < currPos + rowSize() - highlightEnd)
+ pos = currPos + rowSize() - highlightEnd;
+ if (pos > currPos - highlightStart)
+ pos = currPos - highlightStart;
+ if (isRightToLeftTopToBottom())
+ pos = -pos-size(); // Untransform
+ }
+
+ qreal dist = qAbs(data.move + pos);
+ if (dist > 0) {
+ timeline.reset(data.move);
+ if (fixupMode != Immediate) {
+ timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+ data.fixingUp = true;
+ } else {
+ timeline.set(data.move, -pos);
+ }
+ vTime = timeline.time();
+ }
+ } else if (haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
+ if (currentItem) {
+ updateHighlight();
+ qreal pos = currentItem->rowPos();
+ if (viewPos < pos + rowSize() - highlightEnd)
+ viewPos = pos + rowSize() - highlightEnd;
+ if (viewPos > pos - highlightStart)
+ viewPos = pos - highlightStart;
+ if (isRightToLeftTopToBottom())
+ viewPos = -viewPos-size();
+ timeline.reset(data.move);
+ if (viewPos != position()) {
+ if (fixupMode != Immediate) {
+ timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+ data.fixingUp = true;
+ } else {
+ timeline.set(data.move, -viewPos);
+ }
+ }
+ vTime = timeline.time();
+ }
+ } else {
+ QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
+ }
+ fixupMode = Normal;
+}
+
+void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
+{
+ Q_Q(QSGGridView);
+ data.fixingUp = false;
+ moveReason = Mouse;
+ if ((!haveHighlightRange || highlightRange != QSGGridView::StrictlyEnforceRange)
+ && snapMode == QSGGridView::NoSnap) {
+ QSGFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
+ return;
+ }
+ qreal maxDistance = 0;
+ qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
+ // -ve velocity means list is moving up/left
+ if (velocity > 0) {
+ if (data.move.value() < minExtent) {
+ if (snapMode == QSGGridView::SnapOneRow) {
+ if (FxGridItemSG *item = firstVisibleItem())
+ maxDistance = qAbs(item->rowPos() + dataValue);
+ } else {
+ maxDistance = qAbs(minExtent - data.move.value());
+ }
+ }
+ if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
+ data.flickTarget = minExtent;
+ } else {
+ if (data.move.value() > maxExtent) {
+ if (snapMode == QSGGridView::SnapOneRow) {
+ qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize());
+ maxDistance = qAbs(pos + dataValue);
+ } else {
+ maxDistance = qAbs(maxExtent - data.move.value());
+ }
+ }
+ if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
+ data.flickTarget = maxExtent;
+ }
+ bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
+ qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+ if (maxDistance > 0 || overShoot) {
+ // This mode requires the grid to stop exactly on a row boundary.
+ qreal v = velocity;
+ if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
+ if (v < 0)
+ v = -maxVelocity;
+ else
+ v = maxVelocity;
+ }
+ qreal accel = deceleration;
+ qreal v2 = v * v;
+ qreal overshootDist = 0.0;
+ if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QSGGridView::SnapOneRow) {
+ // + rowSize()/4 to encourage moving at least one item in the flick direction
+ qreal dist = v2 / (accel * 2.0) + rowSize()/4;
+ dist = qMin(dist, maxDistance);
+ if (v > 0)
+ dist = -dist;
+ qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
+ data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+ data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
+ qreal adjDist = -data.flickTarget + data.move.value();
+ if (qAbs(adjDist) > qAbs(dist)) {
+ // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
+ qreal adjv2 = accel * 2.0f * qAbs(adjDist);
+ if (adjv2 > v2) {
+ v2 = adjv2;
+ v = qSqrt(v2);
+ if (dist > 0)
+ v = -v;
+ }
+ }
+ dist = adjDist;
+ accel = v2 / (2.0f * qAbs(dist));
+ } else {
+ data.flickTarget = velocity > 0 ? minExtent : maxExtent;
+ overshootDist = overShoot ? overShootDistance(v, vSize) : 0;
+ }
+ timeline.reset(data.move);
+ timeline.accel(data.move, v, accel, maxDistance + overshootDist);
+ timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
+ if (!flickingHorizontally && q->xflick()) {
+ flickingHorizontally = true;
+ emit q->flickingChanged();
+ emit q->flickingHorizontallyChanged();
+ emit q->flickStarted();
+ }
+ if (!flickingVertically && q->yflick()) {
+ flickingVertically = true;
+ emit q->flickingChanged();
+ emit q->flickingVerticallyChanged();
+ emit q->flickStarted();
+ }
+ } else {
+ timeline.reset(data.move);
+ fixup(data, minExtent, maxExtent);
+ }
+}
+
+
+//----------------------------------------------------------------------------
+
+QSGGridView::QSGGridView(QSGItem *parent)
+ : QSGFlickable(*(new QSGGridViewPrivate), parent)
+{
+ Q_D(QSGGridView);
+ d->init();
+}
+
+QSGGridView::~QSGGridView()
+{
+ Q_D(QSGGridView);
+ d->clear();
+ if (d->ownModel)
+ delete d->model;
+ delete d->header;
+ delete d->footer;
+}
+
+// For internal use
+int QSGGridView::modelCount() const
+{
+ Q_D(const QSGGridView);
+ return d->model->count();
+}
+
+QVariant QSGGridView::model() const
+{
+ Q_D(const QSGGridView);
+ return d->modelVariant;
+}
+
+void QSGGridView::setModel(const QVariant &model)
+{
+ Q_D(QSGGridView);
+ if (d->modelVariant == model)
+ return;
+ if (d->model) {
+ disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ }
+ d->clear();
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QSGVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QSGVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this), this);
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ dataModel->setModel(model);
+ }
+ if (d->model) {
+ d->bufferMode = QSGGridViewPrivate::BufferBefore | QSGGridViewPrivate::BufferAfter;
+ if (isComponentComplete()) {
+ refill();
+ if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
+ setCurrentIndex(0);
+ } else {
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGGridViewPrivate::Other;
+ }
+ }
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ emit countChanged();
+ }
+ emit modelChanged();
+}
+
+QDeclarativeComponent *QSGGridView::delegate() const
+{
+ Q_D(const QSGGridView);
+ if (d->model) {
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QSGGridView::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QSGGridView);
+ if (delegate == this->delegate())
+ return;
+
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model)) {
+ dataModel->setDelegate(delegate);
+ if (isComponentComplete()) {
+ for (int i = 0; i < d->visibleItems.count(); ++i)
+ d->releaseItem(d->visibleItems.at(i));
+ d->visibleItems.clear();
+ d->releaseItem(d->currentItem);
+ d->currentItem = 0;
+ refill();
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGGridViewPrivate::Other;
+ }
+ emit delegateChanged();
+ }
+}
+
+int QSGGridView::currentIndex() const
+{
+ Q_D(const QSGGridView);
+ return d->currentIndex;
+}
+
+void QSGGridView::setCurrentIndex(int index)
+{
+ Q_D(QSGGridView);
+ if (d->requestedIndex >= 0) // currently creating item
+ return;
+ d->currentIndexCleared = (index == -1);
+ if (index == d->currentIndex)
+ return;
+ if (isComponentComplete() && d->isValid()) {
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ d->updateCurrent(index);
+ } else {
+ d->currentIndex = index;
+ emit currentIndexChanged();
+ }
+}
+
+QSGItem *QSGGridView::currentItem()
+{
+ Q_D(QSGGridView);
+ if (!d->currentItem)
+ return 0;
+ return d->currentItem->item;
+}
+
+QSGItem *QSGGridView::highlightItem()
+{
+ Q_D(QSGGridView);
+ if (!d->highlight)
+ return 0;
+ return d->highlight->item;
+}
+
+int QSGGridView::count() const
+{
+ Q_D(const QSGGridView);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+QDeclarativeComponent *QSGGridView::highlight() const
+{
+ Q_D(const QSGGridView);
+ return d->highlightComponent;
+}
+
+void QSGGridView::setHighlight(QDeclarativeComponent *highlight)
+{
+ Q_D(QSGGridView);
+ if (highlight != d->highlightComponent) {
+ d->highlightComponent = highlight;
+ d->updateCurrent(d->currentIndex);
+ emit highlightChanged();
+ }
+}
+
+bool QSGGridView::highlightFollowsCurrentItem() const
+{
+ Q_D(const QSGGridView);
+ return d->autoHighlight;
+}
+
+void QSGGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
+{
+ Q_D(QSGGridView);
+ if (d->autoHighlight != autoHighlight) {
+ d->autoHighlight = autoHighlight;
+ if (autoHighlight) {
+ d->updateHighlight();
+ } else if (d->highlightXAnimator) {
+ d->highlightXAnimator->stop();
+ d->highlightYAnimator->stop();
+ }
+ }
+}
+
+int QSGGridView::highlightMoveDuration() const
+{
+ Q_D(const QSGGridView);
+ return d->highlightMoveDuration;
+}
+
+void QSGGridView::setHighlightMoveDuration(int duration)
+{
+ Q_D(QSGGridView);
+ if (d->highlightMoveDuration != duration) {
+ d->highlightMoveDuration = duration;
+ if (d->highlightYAnimator) {
+ d->highlightXAnimator->userDuration = d->highlightMoveDuration;
+ d->highlightYAnimator->userDuration = d->highlightMoveDuration;
+ }
+ emit highlightMoveDurationChanged();
+ }
+}
+
+qreal QSGGridView::preferredHighlightBegin() const
+{
+ Q_D(const QSGGridView);
+ return d->highlightRangeStart;
+}
+
+void QSGGridView::setPreferredHighlightBegin(qreal start)
+{
+ Q_D(QSGGridView);
+ d->highlightRangeStartValid = true;
+ if (d->highlightRangeStart == start)
+ return;
+ d->highlightRangeStart = start;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightBeginChanged();
+}
+
+void QSGGridView::resetPreferredHighlightBegin()
+{
+ Q_D(QSGGridView);
+ d->highlightRangeStartValid = false;
+ if (d->highlightRangeStart == 0)
+ return;
+ d->highlightRangeStart = 0;
+ emit preferredHighlightBeginChanged();
+}
+
+qreal QSGGridView::preferredHighlightEnd() const
+{
+ Q_D(const QSGGridView);
+ return d->highlightRangeEnd;
+}
+
+void QSGGridView::setPreferredHighlightEnd(qreal end)
+{
+ Q_D(QSGGridView);
+ d->highlightRangeEndValid = true;
+ if (d->highlightRangeEnd == end)
+ return;
+ d->highlightRangeEnd = end;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightEndChanged();
+}
+
+void QSGGridView::resetPreferredHighlightEnd()
+{
+ Q_D(QSGGridView);
+ d->highlightRangeEndValid = false;
+ if (d->highlightRangeEnd == 0)
+ return;
+ d->highlightRangeEnd = 0;
+ emit preferredHighlightEndChanged();
+}
+
+QSGGridView::HighlightRangeMode QSGGridView::highlightRangeMode() const
+{
+ Q_D(const QSGGridView);
+ return d->highlightRange;
+}
+
+void QSGGridView::setHighlightRangeMode(HighlightRangeMode mode)
+{
+ Q_D(QSGGridView);
+ if (d->highlightRange == mode)
+ return;
+ d->highlightRange = mode;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit highlightRangeModeChanged();
+}
+
+Qt::LayoutDirection QSGGridView::layoutDirection() const
+{
+ Q_D(const QSGGridView);
+ return d->layoutDirection;
+}
+
+void QSGGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QSGGridView);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ d->regenerate();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+Qt::LayoutDirection QSGGridView::effectiveLayoutDirection() const
+{
+ Q_D(const QSGGridView);
+ if (d->effectiveLayoutMirror)
+ return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return d->layoutDirection;
+}
+
+QSGGridView::Flow QSGGridView::flow() const
+{
+ Q_D(const QSGGridView);
+ return d->flow;
+}
+
+void QSGGridView::setFlow(Flow flow)
+{
+ Q_D(QSGGridView);
+ if (d->flow != flow) {
+ d->flow = flow;
+ if (d->flow == LeftToRight) {
+ setContentWidth(-1);
+ setFlickableDirection(QSGFlickable::VerticalFlick);
+ } else {
+ setContentHeight(-1);
+ setFlickableDirection(QSGFlickable::HorizontalFlick);
+ }
+ setContentX(0);
+ setContentY(0);
+ d->regenerate();
+ emit flowChanged();
+ }
+}
+
+bool QSGGridView::isWrapEnabled() const
+{
+ Q_D(const QSGGridView);
+ return d->wrap;
+}
+
+void QSGGridView::setWrapEnabled(bool wrap)
+{
+ Q_D(QSGGridView);
+ if (d->wrap == wrap)
+ return;
+ d->wrap = wrap;
+ emit keyNavigationWrapsChanged();
+}
+
+int QSGGridView::cacheBuffer() const
+{
+ Q_D(const QSGGridView);
+ return d->buffer;
+}
+
+void QSGGridView::setCacheBuffer(int buffer)
+{
+ Q_D(QSGGridView);
+ if (d->buffer != buffer) {
+ d->buffer = buffer;
+ if (isComponentComplete())
+ refill();
+ emit cacheBufferChanged();
+ }
+}
+
+int QSGGridView::cellWidth() const
+{
+ Q_D(const QSGGridView);
+ return d->cellWidth;
+}
+
+void QSGGridView::setCellWidth(int cellWidth)
+{
+ Q_D(QSGGridView);
+ if (cellWidth != d->cellWidth && cellWidth > 0) {
+ d->cellWidth = qMax(1, cellWidth);
+ d->updateGrid();
+ emit cellWidthChanged();
+ d->layout();
+ }
+}
+
+int QSGGridView::cellHeight() const
+{
+ Q_D(const QSGGridView);
+ return d->cellHeight;
+}
+
+void QSGGridView::setCellHeight(int cellHeight)
+{
+ Q_D(QSGGridView);
+ if (cellHeight != d->cellHeight && cellHeight > 0) {
+ d->cellHeight = qMax(1, cellHeight);
+ d->updateGrid();
+ emit cellHeightChanged();
+ d->layout();
+ }
+}
+
+QSGGridView::SnapMode QSGGridView::snapMode() const
+{
+ Q_D(const QSGGridView);
+ return d->snapMode;
+}
+
+void QSGGridView::setSnapMode(SnapMode mode)
+{
+ Q_D(QSGGridView);
+ if (d->snapMode != mode) {
+ d->snapMode = mode;
+ emit snapModeChanged();
+ }
+}
+
+QDeclarativeComponent *QSGGridView::footer() const
+{
+ Q_D(const QSGGridView);
+ return d->footerComponent;
+}
+
+void QSGGridView::setFooter(QDeclarativeComponent *footer)
+{
+ Q_D(QSGGridView);
+ if (d->footerComponent != footer) {
+ if (d->footer) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ d->footer->item->setParentItem(0);
+ d->footer->item->deleteLater();
+ delete d->footer;
+ d->footer = 0;
+ }
+ d->footerComponent = footer;
+ if (isComponentComplete()) {
+ d->updateFooter();
+ d->updateGrid();
+ d->fixupPosition();
+ }
+ emit footerChanged();
+ }
+}
+
+QDeclarativeComponent *QSGGridView::header() const
+{
+ Q_D(const QSGGridView);
+ return d->headerComponent;
+}
+
+void QSGGridView::setHeader(QDeclarativeComponent *header)
+{
+ Q_D(QSGGridView);
+ if (d->headerComponent != header) {
+ if (d->header) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ d->header->item->setParentItem(0);
+ d->header->item->deleteLater();
+ delete d->header;
+ d->header = 0;
+ }
+ d->headerComponent = header;
+ if (isComponentComplete()) {
+ d->updateHeader();
+ d->updateFooter();
+ d->updateGrid();
+ d->fixupPosition();
+ }
+ emit headerChanged();
+ }
+}
+
+void QSGGridView::setContentX(qreal pos)
+{
+ Q_D(QSGGridView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QSGGridViewPrivate::Other;
+ QSGFlickable::setContentX(pos);
+}
+
+void QSGGridView::setContentY(qreal pos)
+{
+ Q_D(QSGGridView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QSGGridViewPrivate::Other;
+ QSGFlickable::setContentY(pos);
+}
+
+void QSGGridView::updatePolish()
+{
+ Q_D(QSGGridView);
+ QSGFlickable::updatePolish();
+ d->layout();
+}
+
+void QSGGridView::viewportMoved()
+{
+ Q_D(QSGGridView);
+ QSGFlickable::viewportMoved();
+ if (!d->itemCount)
+ return;
+ d->lazyRelease = true;
+ if (d->flickingHorizontally || d->flickingVertically) {
+ if (yflick()) {
+ if (d->vData.velocity > 0)
+ d->bufferMode = QSGGridViewPrivate::BufferBefore;
+ else if (d->vData.velocity < 0)
+ d->bufferMode = QSGGridViewPrivate::BufferAfter;
+ }
+
+ if (xflick()) {
+ if (d->hData.velocity > 0)
+ d->bufferMode = QSGGridViewPrivate::BufferBefore;
+ else if (d->hData.velocity < 0)
+ d->bufferMode = QSGGridViewPrivate::BufferAfter;
+ }
+ }
+ refill();
+ if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
+ d->moveReason = QSGGridViewPrivate::Mouse;
+ if (d->moveReason != QSGGridViewPrivate::SetIndex) {
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
+ // reposition highlight
+ qreal pos = d->highlight->rowPos();
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeftTopToBottom()) {
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ viewPos = -d->position()-d->size();
+ } else {
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ viewPos = d->position();
+ }
+ if (pos > viewPos + highlightEnd - d->rowSize())
+ pos = viewPos + highlightEnd - d->rowSize();
+ if (pos < viewPos + highlightStart)
+ pos = viewPos + highlightStart;
+ d->highlight->setPosition(d->highlight->colPos(), qRound(pos));
+
+ // update current index
+ int idx = d->snapIndex();
+ if (idx >= 0 && idx != d->currentIndex) {
+ d->updateCurrent(idx);
+ if (d->currentItem && d->currentItem->colPos() != d->highlight->colPos() && d->autoHighlight) {
+ if (d->flow == LeftToRight)
+ d->highlightXAnimator->to = d->currentItem->item->x();
+ else
+ d->highlightYAnimator->to = d->currentItem->item->y();
+ }
+ }
+ }
+ }
+}
+
+qreal QSGGridView::minYExtent() const
+{
+ Q_D(const QSGGridView);
+ if (d->flow == QSGGridView::TopToBottom)
+ return QSGFlickable::minYExtent();
+ qreal extent = -d->startPosition();
+ if (d->header && d->visibleItems.count())
+ extent += d->header->item->height();
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ extent += d->highlightRangeStart;
+ extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd));
+ }
+ return extent;
+}
+
+qreal QSGGridView::maxYExtent() const
+{
+ Q_D(const QSGGridView);
+ if (d->flow == QSGGridView::TopToBottom)
+ return QSGFlickable::maxYExtent();
+ qreal extent;
+ if (!d->model || !d->model->count()) {
+ extent = 0;
+ } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart);
+ if (d->highlightRangeEnd != d->highlightRangeStart)
+ extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1));
+ } else {
+ extent = -(d->endPosition() - height());
+ }
+ if (d->footer)
+ extent -= d->footer->item->height();
+ const qreal minY = minYExtent();
+ if (extent > minY)
+ extent = minY;
+ return extent;
+}
+
+qreal QSGGridView::minXExtent() const
+{
+ Q_D(const QSGGridView);
+ if (d->flow == QSGGridView::LeftToRight)
+ return QSGFlickable::minXExtent();
+ qreal extent = -d->startPosition();
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal endPositionFirstItem;
+ if (d->isRightToLeftTopToBottom()) {
+ endPositionFirstItem = d->rowPosAt(d->model->count()-1);
+ highlightStart = d->highlightRangeStartValid
+ ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
+ : d->size() - (d->lastPosition()-endPositionFirstItem);
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
+ if (d->footer && d->visibleItems.count())
+ extent += d->footer->item->width();
+ } else {
+ endPositionFirstItem = d->rowPosAt(0)+d->rowSize();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->header && d->visibleItems.count())
+ extent += d->header->item->width();
+ }
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ extent += highlightStart;
+ extent = qMax(extent, -(endPositionFirstItem - highlightEnd));
+ }
+ return extent;
+}
+
+qreal QSGGridView::maxXExtent() const
+{
+ Q_D(const QSGGridView);
+ if (d->flow == QSGGridView::LeftToRight)
+ return QSGFlickable::maxXExtent();
+ qreal extent;
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal lastItemPosition;
+ if (d->isRightToLeftTopToBottom()){
+ highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
+ lastItemPosition = d->endPosition();
+ } else {
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->model && d->model->count())
+ lastItemPosition = d->rowPosAt(d->model->count()-1);
+ }
+ if (!d->model || !d->model->count()) {
+ extent = 0;
+ } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ extent = -(lastItemPosition - highlightStart);
+ if (highlightEnd != highlightStart)
+ extent = d->isRightToLeftTopToBottom()
+ ? qMax(extent, -(d->endPosition() - highlightEnd + 1))
+ : qMin(extent, -(d->endPosition() - highlightEnd + 1));
+ } else {
+ extent = -(d->endPosition() - width());
+ }
+ if (d->isRightToLeftTopToBottom()) {
+ if (d->header)
+ extent -= d->header->item->width();
+ } else {
+ if (d->footer)
+ extent -= d->footer->item->width();
+ }
+
+ const qreal minX = minXExtent();
+ if (extent > minX)
+ extent = minX;
+ return extent;
+}
+
+void QSGGridView::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QSGGridView);
+ if (d->model && d->model->count() && d->interactive) {
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ int oldCurrent = currentIndex();
+ switch (event->key()) {
+ case Qt::Key_Up:
+ moveCurrentIndexUp();
+ break;
+ case Qt::Key_Down:
+ moveCurrentIndexDown();
+ break;
+ case Qt::Key_Left:
+ moveCurrentIndexLeft();
+ break;
+ case Qt::Key_Right:
+ moveCurrentIndexRight();
+ break;
+ default:
+ break;
+ }
+ if (oldCurrent != currentIndex()) {
+ event->accept();
+ return;
+ }
+ }
+ d->moveReason = QSGGridViewPrivate::Other;
+ event->ignore();
+ QSGFlickable::keyPressEvent(event);
+}
+
+void QSGGridView::moveCurrentIndexUp()
+{
+ Q_D(QSGGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() >= d->columns || d->wrap) {
+ int index = currentIndex() - d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ } else {
+ if (currentIndex() > 0 || d->wrap) {
+ int index = currentIndex() - 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ }
+}
+
+void QSGGridView::moveCurrentIndexDown()
+{
+ Q_D(QSGGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() < count - d->columns || d->wrap) {
+ int index = currentIndex()+d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ } else {
+ if (currentIndex() < count - 1 || d->wrap) {
+ int index = currentIndex() + 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ }
+}
+
+void QSGGridView::moveCurrentIndexLeft()
+{
+ Q_D(QSGGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+ if (effectiveLayoutDirection() == Qt::LeftToRight) {
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() > 0 || d->wrap) {
+ int index = currentIndex() - 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ } else {
+ if (currentIndex() >= d->columns || d->wrap) {
+ int index = currentIndex() - d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ }
+ } else {
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() < count - 1 || d->wrap) {
+ int index = currentIndex() + 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ } else {
+ if (currentIndex() < count - d->columns || d->wrap) {
+ int index = currentIndex() + d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ }
+ }
+}
+
+void QSGGridView::moveCurrentIndexRight()
+{
+ Q_D(QSGGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+ if (effectiveLayoutDirection() == Qt::LeftToRight) {
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() < count - 1 || d->wrap) {
+ int index = currentIndex() + 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ } else {
+ if (currentIndex() < count - d->columns || d->wrap) {
+ int index = currentIndex()+d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ }
+ } else {
+ if (d->flow == QSGGridView::LeftToRight) {
+ if (currentIndex() > 0 || d->wrap) {
+ int index = currentIndex() - 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ } else {
+ if (currentIndex() >= d->columns || d->wrap) {
+ int index = currentIndex() - d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ }
+ }
+}
+
+void QSGGridViewPrivate::positionViewAtIndex(int index, int mode)
+{
+ Q_Q(QSGGridView);
+ if (!isValid())
+ return;
+ if (mode < QSGGridView::Beginning || mode > QSGGridView::Contain)
+ return;
+
+ int idx = qMax(qMin(index, model->count()-1), 0);
+
+ if (layoutScheduled)
+ layout();
+ qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position();
+ FxGridItemSG *item = visibleItem(idx);
+ qreal maxExtent;
+ if (flow == QSGGridView::LeftToRight)
+ maxExtent = -q->maxYExtent();
+ else
+ maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
+ if (!item) {
+ int itemPos = rowPosAt(idx);
+ // save the currently visible items in case any of them end up visible again
+ QList<FxGridItemSG*> oldVisible = visibleItems;
+ visibleItems.clear();
+ visibleIndex = idx - idx % columns;
+ if (flow == QSGGridView::LeftToRight)
+ maxExtent = -q->maxYExtent();
+ else
+ maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
+ setPosition(qMin(qreal(itemPos), maxExtent));
+ // now release the reference to all the old visible items.
+ for (int i = 0; i < oldVisible.count(); ++i)
+ releaseItem(oldVisible.at(i));
+ item = visibleItem(idx);
+ }
+ if (item) {
+ qreal itemPos = item->rowPos();
+ switch (mode) {
+ case QSGGridView::Beginning:
+ pos = itemPos;
+ if (index < 0 && header) {
+ pos -= flow == QSGGridView::LeftToRight
+ ? header->item->height()
+ : header->item->width();
+ }
+ break;
+ case QSGGridView::Center:
+ pos = itemPos - (size() - rowSize())/2;
+ break;
+ case QSGGridView::End:
+ pos = itemPos - size() + rowSize();
+ if (index >= model->count() && footer) {
+ pos += flow == QSGGridView::LeftToRight
+ ? footer->item->height()
+ : footer->item->width();
+ }
+ break;
+ case QSGGridView::Visible:
+ if (itemPos > pos + size())
+ pos = itemPos - size() + rowSize();
+ else if (item->endRowPos() < pos)
+ pos = itemPos;
+ break;
+ case QSGGridView::Contain:
+ if (item->endRowPos() > pos + size())
+ pos = itemPos - size() + rowSize();
+ if (itemPos < pos)
+ pos = itemPos;
+ }
+ pos = qMin(pos, maxExtent);
+ qreal minExtent;
+ if (flow == QSGGridView::LeftToRight)
+ minExtent = -q->minYExtent();
+ else
+ minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent();
+ pos = qMax(pos, minExtent);
+ moveReason = QSGGridViewPrivate::Other;
+ q->cancelFlick();
+ setPosition(pos);
+ }
+ fixupPosition();
+}
+
+void QSGGridView::positionViewAtIndex(int index, int mode)
+{
+ Q_D(QSGGridView);
+ if (!d->isValid() || index < 0 || index >= d->model->count())
+ return;
+ d->positionViewAtIndex(index, mode);
+}
+
+void QSGGridView::positionViewAtBeginning()
+{
+ Q_D(QSGGridView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(-1, Beginning);
+}
+
+void QSGGridView::positionViewAtEnd()
+{
+ Q_D(QSGGridView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(d->model->count(), End);
+}
+
+int QSGGridView::indexAt(qreal x, qreal y) const
+{
+ Q_D(const QSGGridView);
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ const FxGridItemSG *listItem = d->visibleItems.at(i);
+ if(listItem->contains(x, y))
+ return listItem->index;
+ }
+
+ return -1;
+}
+
+void QSGGridView::componentComplete()
+{
+ Q_D(QSGGridView);
+ QSGFlickable::componentComplete();
+ d->updateHeader();
+ d->updateFooter();
+ d->updateGrid();
+ if (d->isValid()) {
+ refill();
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ if (d->currentIndex < 0 && !d->currentIndexCleared)
+ d->updateCurrent(0);
+ else
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGGridViewPrivate::Other;
+ d->fixupPosition();
+ }
+}
+
+void QSGGridView::trackedPositionChanged()
+{
+ Q_D(QSGGridView);
+ if (!d->trackedItem || !d->currentItem)
+ return;
+ if (d->moveReason == QSGGridViewPrivate::SetIndex) {
+ const qreal trackedPos = d->trackedItem->rowPos();
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeftTopToBottom()) {
+ viewPos = -d->position()-d->size();
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ } else {
+ viewPos = d->position();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ }
+ qreal pos = viewPos;
+ if (d->haveHighlightRange) {
+ if (d->highlightRange == StrictlyEnforceRange) {
+ if (trackedPos > pos + highlightEnd - d->rowSize())
+ pos = trackedPos - highlightEnd + d->rowSize();
+ if (trackedPos < pos + highlightStart)
+ pos = trackedPos - highlightStart;
+ } else {
+ if (trackedPos < d->startPosition() + highlightStart) {
+ pos = d->startPosition();
+ } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + highlightEnd) {
+ pos = d->endPosition() - d->size() + 1;
+ if (pos < d->startPosition())
+ pos = d->startPosition();
+ } else {
+ if (trackedPos < viewPos + highlightStart) {
+ pos = trackedPos - highlightStart;
+ } else if (trackedPos > viewPos + highlightEnd - d->rowSize()) {
+ pos = trackedPos - highlightEnd + d->rowSize();
+ }
+ }
+ }
+ } else {
+ if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) {
+ pos = qMax(trackedPos, d->currentItem->rowPos());
+ } else if (d->trackedItem->endRowPos() >= viewPos + d->size()
+ && d->currentItem->endRowPos() >= viewPos + d->size()) {
+ if (d->trackedItem->endRowPos() <= d->currentItem->endRowPos()) {
+ pos = d->trackedItem->endRowPos() - d->size() + 1;
+ if (d->rowSize() > d->size())
+ pos = trackedPos;
+ } else {
+ pos = d->currentItem->endRowPos() - d->size() + 1;
+ if (d->rowSize() > d->size())
+ pos = d->currentItem->rowPos();
+ }
+ }
+ }
+ if (viewPos != pos) {
+ cancelFlick();
+ d->calcVelocity = true;
+ d->setPosition(pos);
+ d->calcVelocity = false;
+ }
+ }
+}
+
+void QSGGridView::itemsInserted(int modelIndex, int count)
+{
+ Q_D(QSGGridView);
+ if (!isComponentComplete())
+ return;
+
+ int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
+ if (index < 0) {
+ int i = d->visibleItems.count() - 1;
+ while (i > 0 && d->visibleItems.at(i)->index == -1)
+ --i;
+ if (d->visibleItems.at(i)->index + 1 == modelIndex) {
+ // Special case of appending an item to the model.
+ index = d->visibleIndex + d->visibleItems.count();
+ } else {
+ if (modelIndex <= d->visibleIndex) {
+ // Insert before visible items
+ d->visibleIndex += count;
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxGridItemSG *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem->index >= modelIndex)
+ listItem->index += count;
+ }
+ }
+ if (d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem)
+ d->currentItem->index = d->currentIndex;
+ emit currentIndexChanged();
+ }
+ d->scheduleLayout();
+ d->itemCount += count;
+ emit countChanged();
+ return;
+ }
+ }
+
+ int insertCount = count;
+ if (index < d->visibleIndex && d->visibleItems.count()) {
+ insertCount -= d->visibleIndex - index;
+ index = d->visibleIndex;
+ modelIndex = d->visibleIndex;
+ }
+
+ qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+width()+1 : d->position();
+ int to = d->buffer+tempPos+d->size()-1;
+ int colPos = 0;
+ int rowPos = 0;
+ if (d->visibleItems.count()) {
+ index -= d->visibleIndex;
+ if (index < d->visibleItems.count()) {
+ colPos = d->visibleItems.at(index)->colPos();
+ rowPos = d->visibleItems.at(index)->rowPos();
+ } else {
+ // appending items to visible list
+ colPos = d->visibleItems.at(index-1)->colPos() + d->colSize();
+ rowPos = d->visibleItems.at(index-1)->rowPos();
+ if (colPos > d->colSize() * (d->columns-1)) {
+ colPos = 0;
+ rowPos += d->rowSize();
+ }
+ }
+ } else if (d->itemCount == 0 && d->header) {
+ rowPos = d->headerSize();
+ }
+
+ // Update the indexes of the following visible items.
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxGridItemSG *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem->index >= modelIndex)
+ listItem->index += count;
+ }
+
+ bool addedVisible = false;
+ QList<FxGridItemSG*> added;
+ int i = 0;
+ while (i < insertCount && rowPos <= to + d->rowSize()*(d->columns - (colPos/d->colSize()))/qreal(d->columns)) {
+ if (!addedVisible) {
+ d->scheduleLayout();
+ addedVisible = true;
+ }
+ FxGridItemSG *item = d->createItem(modelIndex + i);
+ d->visibleItems.insert(index, item);
+ item->setPosition(colPos, rowPos);
+ added.append(item);
+ colPos += d->colSize();
+ if (colPos > d->colSize() * (d->columns-1)) {
+ colPos = 0;
+ rowPos += d->rowSize();
+ }
+ ++index;
+ ++i;
+ }
+ if (i < insertCount) {
+ // We didn't insert all our new items, which means anything
+ // beyond the current index is not visible - remove it.
+ while (d->visibleItems.count() > index) {
+ d->releaseItem(d->visibleItems.takeLast());
+ }
+ }
+
+ // update visibleIndex
+ d->visibleIndex = 0;
+ for (QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ break;
+ }
+ }
+
+ if (d->itemCount && d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem) {
+ d->currentItem->index = d->currentIndex;
+ d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
+ } else if (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared)) {
+ d->updateCurrent(0);
+ }
+ emit currentIndexChanged();
+ } else if (d->itemCount == 0 && d->currentIndex == -1) {
+ setCurrentIndex(0);
+ }
+
+ // everything is in order now - emit add() signal
+ for (int j = 0; j < added.count(); ++j)
+ added.at(j)->attached->emitAdd();
+
+ d->itemCount += count;
+ emit countChanged();
+}
+
+void QSGGridView::itemsRemoved(int modelIndex, int count)
+{
+ Q_D(QSGGridView);
+ if (!isComponentComplete())
+ return;
+
+ d->itemCount -= count;
+ bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count;
+ bool removedVisible = false;
+
+ // Remove the items from the visible list, skipping anything already marked for removal
+ QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxGridItemSG *item = *it;
+ if (item->index == -1 || item->index < modelIndex) {
+ // already removed, or before removed items
+ if (item->index < modelIndex && !removedVisible) {
+ d->scheduleLayout();
+ removedVisible = true;
+ }
+ ++it;
+ } else if (item->index >= modelIndex + count) {
+ // after removed items
+ item->index -= count;
+ ++it;
+ } else {
+ // removed item
+ if (!removedVisible) {
+ d->scheduleLayout();
+ removedVisible = true;
+ }
+ item->attached->emitRemove();
+ if (item->attached->delayRemove()) {
+ item->index = -1;
+ connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
+ ++it;
+ } else {
+ it = d->visibleItems.erase(it);
+ d->releaseItem(item);
+ }
+ }
+ }
+
+ // fix current
+ if (d->currentIndex >= modelIndex + count) {
+ d->currentIndex -= count;
+ if (d->currentItem)
+ d->currentItem->index -= count;
+ emit currentIndexChanged();
+ } else if (currentRemoved) {
+ // current item has been removed.
+ d->releaseItem(d->currentItem);
+ d->currentItem = 0;
+ d->currentIndex = -1;
+ if (d->itemCount)
+ d->updateCurrent(qMin(modelIndex, d->itemCount-1));
+ }
+
+ // update visibleIndex
+ d->visibleIndex = 0;
+ for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ break;
+ }
+ }
+
+ if (removedVisible && d->visibleItems.isEmpty()) {
+ d->timeline.clear();
+ if (d->itemCount == 0) {
+ d->setPosition(0);
+ d->updateHeader();
+ d->updateFooter();
+ }
+ }
+
+ emit countChanged();
+}
+
+void QSGGridView::destroyRemoved()
+{
+ Q_D(QSGGridView);
+ for (QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
+ it != d->visibleItems.end();) {
+ FxGridItemSG *listItem = *it;
+ if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
+ d->releaseItem(listItem);
+ it = d->visibleItems.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Correct the positioning of the items
+ d->layout();
+}
+
+void QSGGridView::itemsMoved(int from, int to, int count)
+{
+ Q_D(QSGGridView);
+ if (!isComponentComplete())
+ return;
+ QHash<int,FxGridItemSG*> moved;
+
+ FxGridItemSG *firstItem = d->firstVisibleItem();
+
+ QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxGridItemSG *item = *it;
+ if (item->index >= from && item->index < from + count) {
+ // take the items that are moving
+ item->index += (to-from);
+ moved.insert(item->index, item);
+ it = d->visibleItems.erase(it);
+ } else {
+ if (item->index > from && item->index != -1) {
+ // move everything after the moved items.
+ item->index -= count;
+ if (item->index < d->visibleIndex)
+ d->visibleIndex = item->index;
+ }
+ ++it;
+ }
+ }
+
+ int remaining = count;
+ int endIndex = d->visibleIndex;
+ it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxGridItemSG *item = *it;
+ if (remaining && item->index >= to && item->index < to + count) {
+ // place items in the target position, reusing any existing items
+ FxGridItemSG *movedItem = moved.take(item->index);
+ if (!movedItem)
+ movedItem = d->createItem(item->index);
+ it = d->visibleItems.insert(it, movedItem);
+ if (it == d->visibleItems.begin() && firstItem)
+ movedItem->setPosition(firstItem->colPos(), firstItem->rowPos());
+ ++it;
+ --remaining;
+ } else {
+ if (item->index != -1) {
+ if (item->index >= to) {
+ // update everything after the moved items.
+ item->index += count;
+ }
+ endIndex = item->index;
+ }
+ ++it;
+ }
+ }
+
+ // If we have moved items to the end of the visible items
+ // then add any existing moved items that we have
+ while (FxGridItemSG *item = moved.take(endIndex+1)) {
+ d->visibleItems.append(item);
+ ++endIndex;
+ }
+
+ // update visibleIndex
+ for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ break;
+ }
+ }
+
+ // Fix current index
+ if (d->currentIndex >= 0 && d->currentItem) {
+ int oldCurrent = d->currentIndex;
+ d->currentIndex = d->model->indexOf(d->currentItem->item, this);
+ if (oldCurrent != d->currentIndex) {
+ d->currentItem->index = d->currentIndex;
+ emit currentIndexChanged();
+ }
+ }
+
+ // Whatever moved items remain are no longer visible items.
+ while (moved.count()) {
+ int idx = moved.begin().key();
+ FxGridItemSG *item = moved.take(idx);
+ if (d->currentItem && item->item == d->currentItem->item)
+ item->setPosition(d->colPosAt(idx), d->rowPosAt(idx));
+ d->releaseItem(item);
+ }
+
+ d->layout();
+}
+
+void QSGGridView::modelReset()
+{
+ Q_D(QSGGridView);
+ d->clear();
+ refill();
+ d->moveReason = QSGGridViewPrivate::SetIndex;
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGGridViewPrivate::Other;
+
+ emit countChanged();
+}
+
+void QSGGridView::createdItem(int index, QSGItem *item)
+{
+ Q_D(QSGGridView);
+ if (d->requestedIndex != index) {
+ item->setParentItem(this);
+ d->unrequestedItems.insert(item, index);
+ if (d->flow == QSGGridView::LeftToRight) {
+ item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index)));
+ } else {
+ item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index)));
+ }
+ }
+}
+
+void QSGGridView::destroyingItem(QSGItem *item)
+{
+ Q_D(QSGGridView);
+ d->unrequestedItems.remove(item);
+}
+
+void QSGGridView::animStopped()
+{
+ Q_D(QSGGridView);
+ d->bufferMode = QSGGridViewPrivate::NoBuffer;
+ if (d->haveHighlightRange && d->highlightRange == QSGGridView::StrictlyEnforceRange)
+ d->updateHighlight();
+}
+
+void QSGGridView::refill()
+{
+ Q_D(QSGGridView);
+ if (d->isRightToLeftTopToBottom())
+ d->refill(-d->position()-d->size()+1, -d->position());
+ else
+ d->refill(d->position(), d->position()+d->size()-1);
+}
+
+
+QSGGridViewAttached *QSGGridView::qmlAttachedProperties(QObject *obj)
+{
+ return new QSGGridViewAttached(obj);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsggridview_p.h b/src/declarative/items/qsggridview_p.h
new file mode 100644
index 0000000000..8eca17df55
--- /dev/null
+++ b/src/declarative/items/qsggridview_p.h
@@ -0,0 +1,290 @@
+// Commit: 95814418f9d6adeba365c795462e8afb00138211
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGGRIDVIEW_P_H
+#define QSGGRIDVIEW_P_H
+
+#include "qsgflickable_p.h"
+
+#include <private/qdeclarativeguard_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QSGVisualModel;
+class QSGGridViewAttached;
+class QSGGridViewPrivate;
+class Q_AUTOTEST_EXPORT QSGGridView : public QSGFlickable
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGGridView)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+ Q_PROPERTY(QSGItem *currentItem READ currentItem NOTIFY currentIndexChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+
+ Q_PROPERTY(QDeclarativeComponent *highlight READ highlight WRITE setHighlight NOTIFY highlightChanged)
+ Q_PROPERTY(QSGItem *highlightItem READ highlightItem NOTIFY highlightItemChanged)
+ Q_PROPERTY(bool highlightFollowsCurrentItem READ highlightFollowsCurrentItem WRITE setHighlightFollowsCurrentItem)
+ Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged)
+
+ Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged RESET resetPreferredHighlightBegin)
+ Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd)
+ Q_PROPERTY(HighlightRangeMode highlightRangeMode READ highlightRangeMode WRITE setHighlightRangeMode NOTIFY highlightRangeModeChanged)
+
+ 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)
+ Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged)
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
+ Q_PROPERTY(int cellWidth READ cellWidth WRITE setCellWidth NOTIFY cellWidthChanged)
+ Q_PROPERTY(int cellHeight READ cellHeight WRITE setCellHeight NOTIFY cellHeightChanged)
+
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
+
+ Q_PROPERTY(QDeclarativeComponent *header READ header WRITE setHeader NOTIFY headerChanged)
+ Q_PROPERTY(QDeclarativeComponent *footer READ footer WRITE setFooter NOTIFY footerChanged)
+
+ Q_ENUMS(HighlightRangeMode)
+ Q_ENUMS(SnapMode)
+ Q_ENUMS(Flow)
+ Q_ENUMS(PositionMode)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ QSGGridView(QSGItem *parent=0);
+ ~QSGGridView();
+
+ QVariant model() const;
+ int modelCount() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ QSGItem *currentItem();
+ QSGItem *highlightItem();
+ int count() const;
+
+ QDeclarativeComponent *highlight() const;
+ void setHighlight(QDeclarativeComponent *highlight);
+
+ bool highlightFollowsCurrentItem() const;
+ void setHighlightFollowsCurrentItem(bool);
+
+ int highlightMoveDuration() const;
+ void setHighlightMoveDuration(int);
+
+ enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange };
+ HighlightRangeMode highlightRangeMode() const;
+ void setHighlightRangeMode(HighlightRangeMode mode);
+
+ qreal preferredHighlightBegin() const;
+ void setPreferredHighlightBegin(qreal);
+ void resetPreferredHighlightBegin();
+
+ qreal preferredHighlightEnd() const;
+ void setPreferredHighlightEnd(qreal);
+ void resetPreferredHighlightEnd();
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection(Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+ enum Flow { LeftToRight, TopToBottom };
+ Flow flow() const;
+ void setFlow(Flow);
+
+ bool isWrapEnabled() const;
+ void setWrapEnabled(bool);
+
+ int cacheBuffer() const;
+ void setCacheBuffer(int);
+
+ int cellWidth() const;
+ void setCellWidth(int);
+
+ int cellHeight() const;
+ void setCellHeight(int);
+
+ enum SnapMode { NoSnap, SnapToRow, SnapOneRow };
+ SnapMode snapMode() const;
+ void setSnapMode(SnapMode mode);
+
+ QDeclarativeComponent *footer() const;
+ void setFooter(QDeclarativeComponent *);
+
+ QDeclarativeComponent *header() const;
+ void setHeader(QDeclarativeComponent *);
+
+ virtual void setContentX(qreal pos);
+ virtual void setContentY(qreal pos);
+
+ enum PositionMode { Beginning, Center, End, Visible, Contain };
+
+ Q_INVOKABLE void positionViewAtIndex(int index, int mode);
+ Q_INVOKABLE int indexAt(qreal x, qreal y) const;
+ Q_INVOKABLE void positionViewAtBeginning();
+ Q_INVOKABLE void positionViewAtEnd();
+
+ static QSGGridViewAttached *qmlAttachedProperties(QObject *);
+
+public Q_SLOTS:
+ void moveCurrentIndexUp();
+ void moveCurrentIndexDown();
+ void moveCurrentIndexLeft();
+ void moveCurrentIndexRight();
+
+Q_SIGNALS:
+ void countChanged();
+ void currentIndexChanged();
+ void cellWidthChanged();
+ void cellHeightChanged();
+ void highlightChanged();
+ void highlightItemChanged();
+ void preferredHighlightBeginChanged();
+ void preferredHighlightEndChanged();
+ void highlightRangeModeChanged();
+ void highlightMoveDurationChanged();
+ void modelChanged();
+ void delegateChanged();
+ void flowChanged();
+ void layoutDirectionChanged();
+ void effectiveLayoutDirectionChanged();
+ void keyNavigationWrapsChanged();
+ void cacheBufferChanged();
+ void snapModeChanged();
+ void headerChanged();
+ void footerChanged();
+
+protected:
+ virtual void updatePolish();
+ virtual void viewportMoved();
+ virtual qreal minYExtent() const;
+ virtual qreal maxYExtent() const;
+ virtual qreal minXExtent() const;
+ virtual qreal maxXExtent() const;
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void componentComplete();
+
+private Q_SLOTS:
+ void trackedPositionChanged();
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int from, int to, int count);
+ void modelReset();
+ void destroyRemoved();
+ void createdItem(int index, QSGItem *item);
+ void destroyingItem(QSGItem *item);
+ void animStopped();
+
+private:
+ void refill();
+};
+
+class QSGGridViewAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QSGGridViewAttached(QObject *parent)
+ : QObject(parent), m_view(0), m_isCurrent(false), m_delayRemove(false) {}
+ ~QSGGridViewAttached() {}
+
+ Q_PROPERTY(QSGGridView *view READ view NOTIFY viewChanged)
+ QSGGridView *view() { return m_view; }
+ void setView(QSGGridView *view) {
+ if (view != m_view) {
+ m_view = view;
+ emit viewChanged();
+ }
+ }
+
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged)
+ bool isCurrentItem() const { return m_isCurrent; }
+ void setIsCurrentItem(bool c) {
+ if (m_isCurrent != c) {
+ m_isCurrent = c;
+ emit currentItemChanged();
+ }
+ }
+
+ Q_PROPERTY(bool delayRemove READ delayRemove WRITE setDelayRemove NOTIFY delayRemoveChanged)
+ bool delayRemove() const { return m_delayRemove; }
+ void setDelayRemove(bool delay) {
+ if (m_delayRemove != delay) {
+ m_delayRemove = delay;
+ emit delayRemoveChanged();
+ }
+ }
+
+ void emitAdd() { emit add(); }
+ void emitRemove() { emit remove(); }
+
+Q_SIGNALS:
+ void currentItemChanged();
+ void delayRemoveChanged();
+ void add();
+ void remove();
+ void viewChanged();
+
+public:
+ QDeclarativeGuard<QSGGridView> m_view;
+ bool m_isCurrent : 1;
+ bool m_delayRemove : 1;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGGridView)
+QML_DECLARE_TYPEINFO(QSGGridView, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+
+#endif // QSGGRIDVIEW_P_H
diff --git a/src/declarative/items/qsgimage.cpp b/src/declarative/items/qsgimage.cpp
new file mode 100644
index 0000000000..6f63555b81
--- /dev/null
+++ b/src/declarative/items/qsgimage.cpp
@@ -0,0 +1,288 @@
+// Commit: 695a39410c8ce186a2ce78cef51093c55fc32643
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgimage_p.h"
+#include "qsgimage_p_p.h"
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+
+#include <QtGui/qpainter.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGImagePrivate::QSGImagePrivate()
+ : fillMode(QSGImage::Stretch)
+ , paintedWidth(0)
+ , paintedHeight(0)
+ , pixmapChanged(false)
+{
+}
+
+QSGImage::QSGImage(QSGItem *parent)
+ : QSGImageBase(*(new QSGImagePrivate), parent)
+{
+}
+
+QSGImage::QSGImage(QSGImagePrivate &dd, QSGItem *parent)
+ : QSGImageBase(dd, parent)
+{
+}
+
+QSGImage::~QSGImage()
+{
+}
+
+void QSGImagePrivate::setPixmap(const QPixmap &pixmap)
+{
+ Q_Q(QSGImage);
+ pix.setPixmap(pixmap);
+
+ q->setImplicitWidth(pix.width());
+ q->setImplicitHeight(pix.height());
+ status = pix.isNull() ? QSGImageBase::Null : QSGImageBase::Ready;
+
+ q->update();
+ q->pixmapChange();
+}
+
+QSGImage::FillMode QSGImage::fillMode() const
+{
+ Q_D(const QSGImage);
+ return d->fillMode;
+}
+
+void QSGImage::setFillMode(FillMode mode)
+{
+ Q_D(QSGImage);
+ if (d->fillMode == mode)
+ return;
+ d->fillMode = mode;
+ update();
+ updatePaintedGeometry();
+ emit fillModeChanged();
+}
+
+qreal QSGImage::paintedWidth() const
+{
+ Q_D(const QSGImage);
+ return d->paintedWidth;
+}
+
+qreal QSGImage::paintedHeight() const
+{
+ Q_D(const QSGImage);
+ return d->paintedHeight;
+}
+
+void QSGImage::updatePaintedGeometry()
+{
+ Q_D(QSGImage);
+
+ if (d->fillMode == PreserveAspectFit) {
+ if (!d->pix.width() || !d->pix.height())
+ return;
+ qreal w = widthValid() ? width() : d->pix.width();
+ qreal widthScale = w / qreal(d->pix.width());
+ qreal h = heightValid() ? height() : d->pix.height();
+ qreal heightScale = h / qreal(d->pix.height());
+ if (widthScale <= heightScale) {
+ d->paintedWidth = w;
+ d->paintedHeight = widthScale * qreal(d->pix.height());
+ } else if(heightScale < widthScale) {
+ d->paintedWidth = heightScale * qreal(d->pix.width());
+ d->paintedHeight = h;
+ }
+ if (widthValid() && !heightValid()) {
+ setImplicitHeight(d->paintedHeight);
+ }
+ if (heightValid() && !widthValid()) {
+ setImplicitWidth(d->paintedWidth);
+ }
+ } else if (d->fillMode == PreserveAspectCrop) {
+ if (!d->pix.width() || !d->pix.height())
+ return;
+ qreal widthScale = width() / qreal(d->pix.width());
+ qreal heightScale = height() / qreal(d->pix.height());
+ if (widthScale < heightScale) {
+ widthScale = heightScale;
+ } else if(heightScale < widthScale) {
+ heightScale = widthScale;
+ }
+
+ d->paintedHeight = heightScale * qreal(d->pix.height());
+ d->paintedWidth = widthScale * qreal(d->pix.width());
+ } else {
+ d->paintedWidth = width();
+ d->paintedHeight = height();
+ }
+ emit paintedGeometryChanged();
+}
+
+void QSGImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QSGImageBase::geometryChanged(newGeometry, oldGeometry);
+ updatePaintedGeometry();
+}
+
+QRectF QSGImage::boundingRect() const
+{
+ Q_D(const QSGImage);
+ return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
+}
+
+QSGTexture *QSGImage::texture() const
+{
+ Q_D(const QSGImage);
+ QSGTexture *t = d->pix.texture();
+ t->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+ t->setMipmapFiltering(QSGTexture::None);
+ t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ t->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ return t;
+}
+
+QSGNode *QSGImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ Q_D(QSGImage);
+ //XXX Support mirror property
+
+ if (!d->pix.texture() || width() <= 0 || height() <= 0) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
+ if (!node) {
+ d->pixmapChanged = true;
+ node = d->sceneGraphContext()->createImageNode();
+ node->setTexture(d->pix.texture());
+ }
+
+ if (d->pixmapChanged) {
+ // force update the texture in the node to trigger reconstruction of
+ // geometry and the likes when a atlas segment has changed.
+ QSGTexture *t = d->pix.texture();
+ node->setTexture(0);
+ node->setTexture(t);
+ d->pixmapChanged = false;
+ }
+
+ QRectF targetRect;
+ QRectF sourceRect;
+ QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
+ QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;
+
+ switch (d->fillMode) {
+ default:
+ case Stretch:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = d->pix.rect();
+ break;
+
+ case PreserveAspectFit:
+ targetRect = QRectF((width() - d->paintedWidth) / 2., (height() - d->paintedHeight) / 2.,
+ d->paintedWidth, d->paintedHeight);
+ sourceRect = d->pix.rect();
+ break;
+
+ case PreserveAspectCrop: {
+ targetRect = QRect(0, 0, width(), height());
+ qreal wscale = width() / qreal(d->pix.width());
+ qreal hscale = height() / qreal(d->pix.height());
+
+ if (wscale > hscale) {
+ int src = (hscale / wscale) * qreal(d->pix.height());
+ sourceRect = QRectF(0, (d->pix.height() - src) / 2, d->pix.width(), src);
+ } else {
+ int src = (wscale / hscale) * qreal(d->pix.width());
+ sourceRect = QRectF((d->pix.width() - src) / 2, 0, src, d->pix.height());
+ }
+ }
+ break;
+
+ case Tile:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = QRectF(0, 0, width(), height());
+ hWrap = QSGTexture::Repeat;
+ vWrap = QSGTexture::Repeat;
+ break;
+
+ case TileHorizontally:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = QRectF(0, 0, width(), d->pix.height());
+ hWrap = QSGTexture::Repeat;
+ break;
+
+ case TileVertically:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = QRectF(0, 0, d->pix.width(), height());
+ vWrap = QSGTexture::Repeat;
+ break;
+
+ };
+
+ QRectF nsrect(sourceRect.x() / d->pix.width(),
+ 1 - sourceRect.y() / d->pix.height(),
+ sourceRect.width() / d->pix.width(),
+ -sourceRect.height() / d->pix.height());
+
+ node->setHorizontalWrapMode(hWrap);
+ node->setVerticalWrapMode(vWrap);
+ node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+
+ node->setTargetRect(targetRect);
+ node->setSourceRect(nsrect);
+ node->update();
+
+ return node;
+}
+
+void QSGImage::pixmapChange()
+{
+ Q_D(QSGImage);
+
+ updatePaintedGeometry();
+ d->pixmapChanged = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgimage_p.h b/src/declarative/items/qsgimage_p.h
new file mode 100644
index 0000000000..aad63d42c0
--- /dev/null
+++ b/src/declarative/items/qsgimage_p.h
@@ -0,0 +1,104 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMAGE_P_H
+#define QSGIMAGE_P_H
+
+#include "qsgimagebase_p.h"
+#include <private/qsgtextureprovider_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGImagePrivate;
+class Q_AUTOTEST_EXPORT QSGImage : public QSGImageBase, public QSGTextureProvider
+{
+ Q_OBJECT
+ Q_ENUMS(FillMode)
+
+ Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
+ Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedGeometryChanged)
+ Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedGeometryChanged)
+ Q_PROPERTY(QSGTexture *texture READ texture)
+
+ Q_INTERFACES(QSGTextureProvider)
+
+public:
+ QSGImage(QSGItem *parent=0);
+ ~QSGImage();
+
+ enum FillMode { Stretch, PreserveAspectFit, PreserveAspectCrop, Tile, TileVertically, TileHorizontally };
+ FillMode fillMode() const;
+ void setFillMode(FillMode);
+
+ qreal paintedWidth() const;
+ qreal paintedHeight() const;
+
+ QRectF boundingRect() const;
+
+ virtual QSGTexture *texture() const;
+
+Q_SIGNALS:
+ void fillModeChanged();
+ void paintedGeometryChanged();
+
+protected:
+ QSGImage(QSGImagePrivate &dd, QSGItem *parent);
+ void pixmapChange();
+ void updatePaintedGeometry();
+
+ virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private:
+ Q_DISABLE_COPY(QSGImage)
+ Q_DECLARE_PRIVATE(QSGImage)
+};
+
+QT_END_NAMESPACE
+QML_DECLARE_TYPE(QSGImage)
+QT_END_HEADER
+
+#endif // QSGIMAGE_P_H
diff --git a/src/declarative/items/qsgimage_p_p.h b/src/declarative/items/qsgimage_p_p.h
new file mode 100644
index 0000000000..01b549df1f
--- /dev/null
+++ b/src/declarative/items/qsgimage_p_p.h
@@ -0,0 +1,81 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMAGE_P_P_H
+#define QSGIMAGE_P_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 "qsgimagebase_p_p.h"
+#include "qsgimage_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGImagePrivate;
+
+class QSGImagePrivate : public QSGImageBasePrivate
+{
+ Q_DECLARE_PUBLIC(QSGImage)
+
+public:
+ QSGImagePrivate();
+
+ QSGImage::FillMode fillMode;
+ qreal paintedWidth;
+ qreal paintedHeight;
+ void setPixmap(const QPixmap &pix);
+
+ bool pixmapChanged : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGIMAGE_P_P_H
diff --git a/src/declarative/items/qsgimagebase.cpp b/src/declarative/items/qsgimagebase.cpp
new file mode 100644
index 0000000000..bd8b24f735
--- /dev/null
+++ b/src/declarative/items/qsgimagebase.cpp
@@ -0,0 +1,273 @@
+// Commit: 462429f5692f810bdd4e04b916db5f9af428d9e4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgimagebase_p.h"
+#include "qsgimagebase_p_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGImageBase::QSGImageBase(QSGItem *parent)
+: QSGImplicitSizeItem(*(new QSGImageBasePrivate), parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QSGImageBase::QSGImageBase(QSGImageBasePrivate &dd, QSGItem *parent)
+: QSGImplicitSizeItem(dd, parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QSGImageBase::~QSGImageBase()
+{
+}
+
+QSGImageBase::Status QSGImageBase::status() const
+{
+ Q_D(const QSGImageBase);
+ return d->status;
+}
+
+
+qreal QSGImageBase::progress() const
+{
+ Q_D(const QSGImageBase);
+ return d->progress;
+}
+
+
+bool QSGImageBase::asynchronous() const
+{
+ Q_D(const QSGImageBase);
+ return d->async;
+}
+
+void QSGImageBase::setAsynchronous(bool async)
+{
+ Q_D(QSGImageBase);
+ if (d->async != async) {
+ d->async = async;
+ emit asynchronousChanged();
+ }
+}
+
+QUrl QSGImageBase::source() const
+{
+ Q_D(const QSGImageBase);
+ return d->url;
+}
+
+void QSGImageBase::setSource(const QUrl &url)
+{
+ Q_D(QSGImageBase);
+ //equality is fairly expensive, so we bypass for simple, common case
+ if ((d->url.isEmpty() == url.isEmpty()) && url == d->url)
+ return;
+
+ d->url = url;
+ emit sourceChanged(d->url);
+
+ if (isComponentComplete())
+ load();
+}
+
+void QSGImageBase::setSourceSize(const QSize& size)
+{
+ Q_D(QSGImageBase);
+ if (d->sourcesize == size)
+ return;
+
+ d->sourcesize = size;
+ d->explicitSourceSize = true;
+ emit sourceSizeChanged();
+ if (isComponentComplete())
+ load();
+}
+
+QSize QSGImageBase::sourceSize() const
+{
+ Q_D(const QSGImageBase);
+
+ int width = d->sourcesize.width();
+ int height = d->sourcesize.height();
+ return QSize(width != -1 ? width : d->pix.width(), height != -1 ? height : d->pix.height());
+}
+
+bool QSGImageBase::cache() const
+{
+ Q_D(const QSGImageBase);
+ return d->cache;
+}
+
+void QSGImageBase::setCache(bool cache)
+{
+ Q_D(QSGImageBase);
+ if (d->cache == cache)
+ return;
+
+ d->cache = cache;
+ emit cacheChanged();
+ if (isComponentComplete())
+ load();
+}
+
+void QSGImageBase::setMirror(bool mirror)
+{
+ Q_D(QSGImageBase);
+ if (mirror == d->mirror)
+ return;
+
+ d->mirror = mirror;
+
+ if (isComponentComplete())
+ update();
+
+ emit mirrorChanged();
+}
+
+bool QSGImageBase::mirror() const
+{
+ Q_D(const QSGImageBase);
+ return d->mirror;
+}
+
+void QSGImageBase::load()
+{
+ Q_D(QSGImageBase);
+
+ if (d->url.isEmpty()) {
+ d->pix.clear(this);
+ d->status = Null;
+ d->progress = 0.0;
+ setImplicitWidth(0);
+ setImplicitHeight(0);
+ emit progressChanged(d->progress);
+ emit statusChanged(d->status);
+ pixmapChange();
+ update();
+ } else {
+ QDeclarativePixmap::Options options;
+ if (d->async)
+ options |= QDeclarativePixmap::Asynchronous;
+ if (d->cache)
+ options |= QDeclarativePixmap::Cache;
+ d->pix.clear(this);
+ d->pix.load(qmlEngine(this), d->url, d->explicitSourceSize ? sourceSize() : QSize(), options);
+
+ if (d->pix.isLoading()) {
+ d->progress = 0.0;
+ d->status = Loading;
+ emit progressChanged(d->progress);
+ emit statusChanged(d->status);
+
+ static int thisRequestProgress = -1;
+ static int thisRequestFinished = -1;
+ if (thisRequestProgress == -1) {
+ thisRequestProgress =
+ QSGImageBase::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
+ thisRequestFinished =
+ QSGImageBase::staticMetaObject.indexOfSlot("requestFinished()");
+ }
+
+ d->pix.connectFinished(this, thisRequestFinished);
+ d->pix.connectDownloadProgress(this, thisRequestProgress);
+
+ } else {
+ requestFinished();
+ }
+ }
+}
+
+void QSGImageBase::requestFinished()
+{
+ Q_D(QSGImageBase);
+
+ QSGImageBase::Status oldStatus = d->status;
+ qreal oldProgress = d->progress;
+
+ if (d->pix.isError()) {
+ d->status = Error;
+ qmlInfo(this) << d->pix.error();
+ } else {
+ d->status = Ready;
+ }
+
+ d->progress = 1.0;
+
+ setImplicitWidth(d->pix.width());
+ setImplicitHeight(d->pix.height());
+
+ if (d->sourcesize.width() != d->pix.width() || d->sourcesize.height() != d->pix.height())
+ emit sourceSizeChanged();
+
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
+ if (d->progress != oldProgress)
+ emit progressChanged(d->progress);
+ pixmapChange();
+ update();
+}
+
+void QSGImageBase::requestProgress(qint64 received, qint64 total)
+{
+ Q_D(QSGImageBase);
+ if (d->status == Loading && total > 0) {
+ d->progress = qreal(received)/total;
+ emit progressChanged(d->progress);
+ }
+}
+
+void QSGImageBase::componentComplete()
+{
+ Q_D(QSGImageBase);
+ QSGItem::componentComplete();
+ if (d->url.isValid())
+ load();
+}
+
+void QSGImageBase::pixmapChange()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgimagebase_p.h b/src/declarative/items/qsgimagebase_p.h
new file mode 100644
index 0000000000..fe42854304
--- /dev/null
+++ b/src/declarative/items/qsgimagebase_p.h
@@ -0,0 +1,116 @@
+// Commit: ab71df83ba4eb9d749efc0f3a2d4a0fe5486023f
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMAGEBASE_P_H
+#define QSGIMAGEBASE_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGImageBasePrivate;
+class Q_AUTOTEST_EXPORT QSGImageBase : public QSGImplicitSizeItem
+{
+ Q_OBJECT
+ Q_ENUMS(Status)
+
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+ Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged)
+ Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged)
+ Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize NOTIFY sourceSizeChanged)
+ Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged)
+
+public:
+ QSGImageBase(QSGItem *parent=0);
+ ~QSGImageBase();
+ enum Status { Null, Ready, Loading, Error };
+ Status status() const;
+ qreal progress() const;
+
+ QUrl source() const;
+ virtual void setSource(const QUrl &url);
+
+ bool asynchronous() const;
+ void setAsynchronous(bool);
+
+ bool cache() const;
+ void setCache(bool);
+
+ virtual void setSourceSize(const QSize&);
+ QSize sourceSize() const;
+
+ virtual void setMirror(bool mirror);
+ bool mirror() const;
+
+Q_SIGNALS:
+ void sourceChanged(const QUrl &);
+ void sourceSizeChanged();
+ void statusChanged(QSGImageBase::Status);
+ void progressChanged(qreal progress);
+ void asynchronousChanged();
+ void cacheChanged();
+ void mirrorChanged();
+
+protected:
+ virtual void load();
+ virtual void componentComplete();
+ virtual void pixmapChange();
+ QSGImageBase(QSGImageBasePrivate &dd, QSGItem *parent);
+
+private Q_SLOTS:
+ virtual void requestFinished();
+ void requestProgress(qint64,qint64);
+
+private:
+ Q_DISABLE_COPY(QSGImageBase)
+ Q_DECLARE_PRIVATE(QSGImageBase)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGIMAGEBASE_P_H
diff --git a/src/declarative/items/qsgimagebase_p_p.h b/src/declarative/items/qsgimagebase_p_p.h
new file mode 100644
index 0000000000..8c67b41e8b
--- /dev/null
+++ b/src/declarative/items/qsgimagebase_p_p.h
@@ -0,0 +1,93 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMAGEBASE_P_P_H
+#define QSGIMAGEBASE_P_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 "qsgimplicitsizeitem_p_p.h"
+#include "qsgimagebase_p.h"
+
+#include <private/qdeclarativepixmapcache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QSGImageBasePrivate : public QSGImplicitSizeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGImageBase)
+
+public:
+ QSGImageBasePrivate()
+ : status(QSGImageBase::Null),
+ progress(0.0),
+ explicitSourceSize(false),
+ async(false),
+ cache(true),
+ mirror(false)
+ {
+ }
+
+ QDeclarativePixmap pix;
+ QSGImageBase::Status status;
+ QUrl url;
+ qreal progress;
+ QSize sourcesize;
+ bool explicitSourceSize : 1;
+ bool async : 1;
+ bool cache : 1;
+ bool mirror: 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGIMAGEBASE_P_P_H
diff --git a/src/declarative/items/qsgimplicitsizeitem.cpp b/src/declarative/items/qsgimplicitsizeitem.cpp
new file mode 100644
index 0000000000..f2cc9bcbdb
--- /dev/null
+++ b/src/declarative/items/qsgimplicitsizeitem.cpp
@@ -0,0 +1,93 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qsgimplicitsizeitem_p.h"
+#include "private/qsgimplicitsizeitem_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QSGImplicitSizeItemPrivate::implicitWidthChanged()
+{
+ Q_Q(QSGImplicitSizeItem);
+ emit q->implicitWidthChanged();
+}
+
+void QSGImplicitSizeItemPrivate::implicitHeightChanged()
+{
+ Q_Q(QSGImplicitSizeItem);
+ emit q->implicitHeightChanged();
+}
+
+QSGImplicitSizeItem::QSGImplicitSizeItem(QSGItem *parent)
+ : QSGItem(*(new QSGImplicitSizeItemPrivate), parent)
+{
+}
+
+QSGImplicitSizeItem::QSGImplicitSizeItem(QSGImplicitSizeItemPrivate &dd, QSGItem *parent)
+ : QSGItem(dd, parent)
+{
+}
+
+
+void QSGImplicitSizePaintedItemPrivate::implicitWidthChanged()
+{
+ Q_Q(QSGImplicitSizePaintedItem);
+ emit q->implicitWidthChanged();
+}
+
+void QSGImplicitSizePaintedItemPrivate::implicitHeightChanged()
+{
+ Q_Q(QSGImplicitSizePaintedItem);
+ emit q->implicitHeightChanged();
+}
+
+QSGImplicitSizePaintedItem::QSGImplicitSizePaintedItem(QSGItem *parent)
+ : QSGPaintedItem(*(new QSGImplicitSizePaintedItemPrivate), parent)
+{
+}
+
+QSGImplicitSizePaintedItem::QSGImplicitSizePaintedItem(QSGImplicitSizePaintedItemPrivate &dd, QSGItem *parent)
+ : QSGPaintedItem(dd, parent)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgimplicitsizeitem_p.h b/src/declarative/items/qsgimplicitsizeitem_p.h
new file mode 100644
index 0000000000..36ef0e7f8b
--- /dev/null
+++ b/src/declarative/items/qsgimplicitsizeitem_p.h
@@ -0,0 +1,101 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMPLICITSIZEITEM_H
+#define QSGIMPLICITSIZEITEM_H
+
+#include "qsgpainteditem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGImplicitSizeItemPrivate;
+class Q_AUTOTEST_EXPORT QSGImplicitSizeItem : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged)
+
+public:
+ QSGImplicitSizeItem(QSGItem *parent = 0);
+
+protected:
+ QSGImplicitSizeItem(QSGImplicitSizeItemPrivate &dd, QSGItem *parent);
+
+Q_SIGNALS:
+ void implicitWidthChanged();
+ void implicitHeightChanged();
+
+private:
+ Q_DISABLE_COPY(QSGImplicitSizeItem)
+ Q_DECLARE_PRIVATE(QSGImplicitSizeItem)
+};
+
+class QSGImplicitSizePaintedItemPrivate;
+class Q_AUTOTEST_EXPORT QSGImplicitSizePaintedItem : public QSGPaintedItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged)
+
+public:
+ QSGImplicitSizePaintedItem(QSGItem *parent = 0);
+
+protected:
+ QSGImplicitSizePaintedItem(QSGImplicitSizePaintedItemPrivate &dd, QSGItem *parent);
+ virtual void drawContents(QPainter *, const QRect &) {};
+
+Q_SIGNALS:
+ void implicitWidthChanged();
+ void implicitHeightChanged();
+
+private:
+ Q_DISABLE_COPY(QSGImplicitSizePaintedItem)
+ Q_DECLARE_PRIVATE(QSGImplicitSizePaintedItem)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGIMPLICITSIZEITEM_H
diff --git a/src/declarative/items/qsgimplicitsizeitem_p_p.h b/src/declarative/items/qsgimplicitsizeitem_p_p.h
new file mode 100644
index 0000000000..f67ecfab9f
--- /dev/null
+++ b/src/declarative/items/qsgimplicitsizeitem_p_p.h
@@ -0,0 +1,92 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGIMPLICITSIZEITEM_P_H
+#define QSGIMPLICITSIZEITEM_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/qsgitem_p.h"
+#include "private/qsgpainteditem_p.h"
+#include "private/qsgimplicitsizeitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGImplicitSizeItemPrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGImplicitSizeItem)
+
+public:
+ QSGImplicitSizeItemPrivate()
+ {
+ }
+
+ virtual void implicitWidthChanged();
+ virtual void implicitHeightChanged();
+};
+
+
+class QSGImplicitSizePaintedItemPrivate : public QSGPaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGImplicitSizePaintedItem)
+
+public:
+ QSGImplicitSizePaintedItemPrivate()
+ {
+ }
+
+ virtual void implicitWidthChanged();
+ virtual void implicitHeightChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGIMPLICITSIZEITEM_P_H
diff --git a/src/declarative/items/qsgitem.cpp b/src/declarative/items/qsgitem.cpp
new file mode 100644
index 0000000000..b0df6b1a04
--- /dev/null
+++ b/src/declarative/items/qsgitem.cpp
@@ -0,0 +1,3143 @@
+// Commit: c44be8c0b27756a2025ebad1945632f3f7e4bebc
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgitem.h"
+
+#include "qsgcanvas.h"
+#include <QtScript/qscriptengine.h>
+#include "qsgcanvas_p.h"
+
+#include "qsgevents_p_p.h"
+
+#include <QtDeclarative/qdeclarativeitem.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativeview.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qgraphicstransform.h>
+#include <QtGui/qpen.h>
+#include <QtGui/qinputcontext.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qnumeric.h>
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativestategroup_p.h>
+#include <private/qdeclarativeopenmetaobject_p.h>
+#include <private/qdeclarativestate_p.h>
+#include <private/qlistmodelinterface_p.h>
+#include <private/qsgitem_p.h>
+
+#include <float.h>
+
+// XXX todo Readd parentNotifier for faster parent bindings
+// XXX todo Check that elements that create items handle memory correctly after visual ownership change
+
+QT_BEGIN_NAMESPACE
+
+QSGTransformPrivate::QSGTransformPrivate()
+{
+}
+
+QSGTransform::QSGTransform(QObject *parent)
+: QObject(*(new QSGTransformPrivate), parent)
+{
+}
+
+QSGTransform::QSGTransform(QSGTransformPrivate &dd, QObject *parent)
+: QObject(dd, parent)
+{
+}
+
+QSGTransform::~QSGTransform()
+{
+ Q_D(QSGTransform);
+ for (int ii = 0; ii < d->items.count(); ++ii) {
+ QSGItemPrivate *p = QSGItemPrivate::get(d->items.at(ii));
+ p->transforms.removeOne(this);
+ p->dirty(QSGItemPrivate::Transform);
+ }
+}
+
+void QSGTransform::update()
+{
+ Q_D(QSGTransform);
+ for (int ii = 0; ii < d->items.count(); ++ii) {
+ QSGItemPrivate *p = QSGItemPrivate::get(d->items.at(ii));
+ p->dirty(QSGItemPrivate::Transform);
+ }
+}
+
+QSGContents::QSGContents(QSGItem *item)
+: m_item(item), m_x(0), m_y(0), m_width(0), m_height(0)
+{
+ //### optimize
+ connect(this, SIGNAL(rectChanged(QRectF)), m_item, SIGNAL(childrenRectChanged(QRectF)));
+}
+
+QSGContents::~QSGContents()
+{
+ QList<QSGItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QSGItem *child = children.at(i);
+ QSGItemPrivate::get(child)->removeItemChangeListener(this, QSGItemPrivate::Geometry | QSGItemPrivate::Destroyed);
+ }
+}
+
+QRectF QSGContents::rectF() const
+{
+ return QRectF(m_x, m_y, m_width, m_height);
+}
+
+void QSGContents::calcHeight(QSGItem *changed)
+{
+ qreal oldy = m_y;
+ qreal oldheight = m_height;
+
+ if (changed) {
+ qreal top = oldy;
+ qreal bottom = oldy + oldheight;
+ qreal y = changed->y();
+ if (y + changed->height() > bottom)
+ bottom = y + changed->height();
+ if (y < top)
+ top = y;
+ m_y = top;
+ m_height = bottom - top;
+ } else {
+ qreal top = FLT_MAX;
+ qreal bottom = 0;
+ QList<QSGItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QSGItem *child = children.at(i);
+ qreal y = child->y();
+ if (y + child->height() > bottom)
+ bottom = y + child->height();
+ if (y < top)
+ top = y;
+ }
+ if (!children.isEmpty())
+ m_y = top;
+ m_height = qMax(bottom - top, qreal(0.0));
+ }
+
+ if (m_height != oldheight || m_y != oldy)
+ emit rectChanged(rectF());
+}
+
+void QSGContents::calcWidth(QSGItem *changed)
+{
+ qreal oldx = m_x;
+ qreal oldwidth = m_width;
+
+ if (changed) {
+ qreal left = oldx;
+ qreal right = oldx + oldwidth;
+ qreal x = changed->x();
+ if (x + changed->width() > right)
+ right = x + changed->width();
+ if (x < left)
+ left = x;
+ m_x = left;
+ m_width = right - left;
+ } else {
+ qreal left = FLT_MAX;
+ qreal right = 0;
+ QList<QSGItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QSGItem *child = children.at(i);
+ qreal x = child->x();
+ if (x + child->width() > right)
+ right = x + child->width();
+ if (x < left)
+ left = x;
+ }
+ if (!children.isEmpty())
+ m_x = left;
+ m_width = qMax(right - left, qreal(0.0));
+ }
+
+ if (m_width != oldwidth || m_x != oldx)
+ emit rectChanged(rectF());
+}
+
+void QSGContents::complete()
+{
+ QList<QSGItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QSGItem *child = children.at(i);
+ QSGItemPrivate::get(child)->addItemChangeListener(this, QSGItemPrivate::Geometry | QSGItemPrivate::Destroyed);
+ //###what about changes to visibility?
+ }
+
+ calcGeometry();
+}
+
+void QSGContents::itemGeometryChanged(QSGItem *changed, const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_UNUSED(changed)
+ //### we can only pass changed if the left edge has moved left, or the right edge has moved right
+ if (newGeometry.width() != oldGeometry.width() || newGeometry.x() != oldGeometry.x())
+ calcWidth(/*changed*/);
+ if (newGeometry.height() != oldGeometry.height() || newGeometry.y() != oldGeometry.y())
+ calcHeight(/*changed*/);
+}
+
+void QSGContents::itemDestroyed(QSGItem *item)
+{
+ if (item)
+ QSGItemPrivate::get(item)->removeItemChangeListener(this, QSGItemPrivate::Geometry | QSGItemPrivate::Destroyed);
+ calcGeometry();
+}
+
+void QSGContents::childRemoved(QSGItem *item)
+{
+ if (item)
+ QSGItemPrivate::get(item)->removeItemChangeListener(this, QSGItemPrivate::Geometry | QSGItemPrivate::Destroyed);
+ calcGeometry();
+}
+
+void QSGContents::childAdded(QSGItem *item)
+{
+ if (item)
+ QSGItemPrivate::get(item)->addItemChangeListener(this, QSGItemPrivate::Geometry | QSGItemPrivate::Destroyed);
+ calcWidth(item);
+ calcHeight(item);
+}
+
+QSGItemKeyFilter::QSGItemKeyFilter(QSGItem *item)
+: m_processPost(false), m_next(0)
+{
+ QSGItemPrivate *p = item?QSGItemPrivate::get(item):0;
+ if (p) {
+ m_next = p->keyHandler;
+ p->keyHandler = this;
+ }
+}
+
+QSGItemKeyFilter::~QSGItemKeyFilter()
+{
+}
+
+void QSGItemKeyFilter::keyPressed(QKeyEvent *event, bool post)
+{
+ if (m_next) m_next->keyPressed(event, post);
+}
+
+void QSGItemKeyFilter::keyReleased(QKeyEvent *event, bool post)
+{
+ if (m_next) m_next->keyReleased(event, post);
+}
+
+void QSGItemKeyFilter::inputMethodEvent(QInputMethodEvent *event, bool post)
+{
+ if (m_next)
+ m_next->inputMethodEvent(event, post);
+ else
+ event->ignore();
+}
+
+QVariant QSGItemKeyFilter::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ if (m_next) return m_next->inputMethodQuery(query);
+ return QVariant();
+}
+
+void QSGItemKeyFilter::componentComplete()
+{
+ if (m_next) m_next->componentComplete();
+}
+
+QSGKeyNavigationAttached::QSGKeyNavigationAttached(QObject *parent)
+: QObject(*(new QSGKeyNavigationAttachedPrivate), parent),
+ QSGItemKeyFilter(qobject_cast<QSGItem*>(parent))
+{
+ m_processPost = true;
+}
+
+QSGKeyNavigationAttached *
+QSGKeyNavigationAttached::qmlAttachedProperties(QObject *obj)
+{
+ return new QSGKeyNavigationAttached(obj);
+}
+
+QSGItem *QSGKeyNavigationAttached::left() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->left;
+}
+
+void QSGKeyNavigationAttached::setLeft(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->left == i)
+ return;
+ d->left = i;
+ d->leftSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if (other && !other->d_func()->rightSet){
+ other->d_func()->right = qobject_cast<QSGItem*>(parent());
+ emit other->rightChanged();
+ }
+ emit leftChanged();
+}
+
+QSGItem *QSGKeyNavigationAttached::right() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->right;
+}
+
+void QSGKeyNavigationAttached::setRight(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->right == i)
+ return;
+ d->right = i;
+ d->rightSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if (other && !other->d_func()->leftSet){
+ other->d_func()->left = qobject_cast<QSGItem*>(parent());
+ emit other->leftChanged();
+ }
+ emit rightChanged();
+}
+
+QSGItem *QSGKeyNavigationAttached::up() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->up;
+}
+
+void QSGKeyNavigationAttached::setUp(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->up == i)
+ return;
+ d->up = i;
+ d->upSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if (other && !other->d_func()->downSet){
+ other->d_func()->down = qobject_cast<QSGItem*>(parent());
+ emit other->downChanged();
+ }
+ emit upChanged();
+}
+
+QSGItem *QSGKeyNavigationAttached::down() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->down;
+}
+
+void QSGKeyNavigationAttached::setDown(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->down == i)
+ return;
+ d->down = i;
+ d->downSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if(other && !other->d_func()->upSet){
+ other->d_func()->up = qobject_cast<QSGItem*>(parent());
+ emit other->upChanged();
+ }
+ emit downChanged();
+}
+
+QSGItem *QSGKeyNavigationAttached::tab() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->tab;
+}
+
+void QSGKeyNavigationAttached::setTab(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->tab == i)
+ return;
+ d->tab = i;
+ d->tabSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if(other && !other->d_func()->backtabSet){
+ other->d_func()->backtab = qobject_cast<QSGItem*>(parent());
+ emit other->backtabChanged();
+ }
+ emit tabChanged();
+}
+
+QSGItem *QSGKeyNavigationAttached::backtab() const
+{
+ Q_D(const QSGKeyNavigationAttached);
+ return d->backtab;
+}
+
+void QSGKeyNavigationAttached::setBacktab(QSGItem *i)
+{
+ Q_D(QSGKeyNavigationAttached);
+ if (d->backtab == i)
+ return;
+ d->backtab = i;
+ d->backtabSet = true;
+ QSGKeyNavigationAttached* other =
+ qobject_cast<QSGKeyNavigationAttached*>(qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(i));
+ if(other && !other->d_func()->tabSet){
+ other->d_func()->tab = qobject_cast<QSGItem*>(parent());
+ emit other->tabChanged();
+ }
+ emit backtabChanged();
+}
+
+QSGKeyNavigationAttached::Priority QSGKeyNavigationAttached::priority() const
+{
+ return m_processPost ? AfterItem : BeforeItem;
+}
+
+void QSGKeyNavigationAttached::setPriority(Priority order)
+{
+ bool processPost = order == AfterItem;
+ if (processPost != m_processPost) {
+ m_processPost = processPost;
+ emit priorityChanged();
+ }
+}
+
+void QSGKeyNavigationAttached::keyPressed(QKeyEvent *event, bool post)
+{
+ Q_D(QSGKeyNavigationAttached);
+ event->ignore();
+
+ if (post != m_processPost) {
+ QSGItemKeyFilter::keyPressed(event, post);
+ return;
+ }
+
+ bool mirror = false;
+ switch(event->key()) {
+ case Qt::Key_Left: {
+ if (QSGItem *parentItem = qobject_cast<QSGItem*>(parent()))
+ mirror = QSGItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ QSGItem* leftItem = mirror ? d->right : d->left;
+ if (leftItem) {
+ setFocusNavigation(leftItem, mirror ? "right" : "left");
+ event->accept();
+ }
+ break;
+ }
+ case Qt::Key_Right: {
+ if (QSGItem *parentItem = qobject_cast<QSGItem*>(parent()))
+ mirror = QSGItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ QSGItem* rightItem = mirror ? d->left : d->right;
+ if (rightItem) {
+ setFocusNavigation(rightItem, mirror ? "left" : "right");
+ event->accept();
+ }
+ break;
+ }
+ case Qt::Key_Up:
+ if (d->up) {
+ setFocusNavigation(d->up, "up");
+ event->accept();
+ }
+ break;
+ case Qt::Key_Down:
+ if (d->down) {
+ setFocusNavigation(d->down, "down");
+ event->accept();
+ }
+ break;
+ case Qt::Key_Tab:
+ if (d->tab) {
+ setFocusNavigation(d->tab, "tab");
+ event->accept();
+ }
+ break;
+ case Qt::Key_Backtab:
+ if (d->backtab) {
+ setFocusNavigation(d->backtab, "backtab");
+ event->accept();
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!event->isAccepted()) QSGItemKeyFilter::keyPressed(event, post);
+}
+
+void QSGKeyNavigationAttached::keyReleased(QKeyEvent *event, bool post)
+{
+ Q_D(QSGKeyNavigationAttached);
+ event->ignore();
+
+ if (post != m_processPost) {
+ QSGItemKeyFilter::keyReleased(event, post);
+ return;
+ }
+
+ bool mirror = false;
+ switch(event->key()) {
+ case Qt::Key_Left:
+ if (QSGItem *parentItem = qobject_cast<QSGItem*>(parent()))
+ mirror = QSGItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ if (mirror ? d->right : d->left)
+ event->accept();
+ break;
+ case Qt::Key_Right:
+ if (QSGItem *parentItem = qobject_cast<QSGItem*>(parent()))
+ mirror = QSGItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ if (mirror ? d->left : d->right)
+ event->accept();
+ break;
+ case Qt::Key_Up:
+ if (d->up) {
+ event->accept();
+ }
+ break;
+ case Qt::Key_Down:
+ if (d->down) {
+ event->accept();
+ }
+ break;
+ case Qt::Key_Tab:
+ if (d->tab) {
+ event->accept();
+ }
+ break;
+ case Qt::Key_Backtab:
+ if (d->backtab) {
+ event->accept();
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!event->isAccepted()) QSGItemKeyFilter::keyReleased(event, post);
+}
+
+void QSGKeyNavigationAttached::setFocusNavigation(QSGItem *currentItem, const char *dir)
+{
+ QSGItem *initialItem = currentItem;
+ bool isNextItem = false;
+ do {
+ isNextItem = false;
+ if (currentItem->isVisible() && currentItem->isEnabled()) {
+ currentItem->setFocus(true);
+ } else {
+ QObject *attached =
+ qmlAttachedPropertiesObject<QSGKeyNavigationAttached>(currentItem, false);
+ if (attached) {
+ QSGItem *tempItem = qvariant_cast<QSGItem*>(attached->property(dir));
+ if (tempItem) {
+ currentItem = tempItem;
+ isNextItem = true;
+ }
+ }
+ }
+ }
+ while (currentItem != initialItem && isNextItem);
+}
+
+const QSGKeysAttached::SigMap QSGKeysAttached::sigMap[] = {
+ { Qt::Key_Left, "leftPressed" },
+ { Qt::Key_Right, "rightPressed" },
+ { Qt::Key_Up, "upPressed" },
+ { Qt::Key_Down, "downPressed" },
+ { Qt::Key_Tab, "tabPressed" },
+ { Qt::Key_Backtab, "backtabPressed" },
+ { Qt::Key_Asterisk, "asteriskPressed" },
+ { Qt::Key_NumberSign, "numberSignPressed" },
+ { Qt::Key_Escape, "escapePressed" },
+ { Qt::Key_Return, "returnPressed" },
+ { Qt::Key_Enter, "enterPressed" },
+ { Qt::Key_Delete, "deletePressed" },
+ { Qt::Key_Space, "spacePressed" },
+ { Qt::Key_Back, "backPressed" },
+ { Qt::Key_Cancel, "cancelPressed" },
+ { Qt::Key_Select, "selectPressed" },
+ { Qt::Key_Yes, "yesPressed" },
+ { Qt::Key_No, "noPressed" },
+ { Qt::Key_Context1, "context1Pressed" },
+ { Qt::Key_Context2, "context2Pressed" },
+ { Qt::Key_Context3, "context3Pressed" },
+ { Qt::Key_Context4, "context4Pressed" },
+ { Qt::Key_Call, "callPressed" },
+ { Qt::Key_Hangup, "hangupPressed" },
+ { Qt::Key_Flip, "flipPressed" },
+ { Qt::Key_Menu, "menuPressed" },
+ { Qt::Key_VolumeUp, "volumeUpPressed" },
+ { Qt::Key_VolumeDown, "volumeDownPressed" },
+ { 0, 0 }
+};
+
+bool QSGKeysAttachedPrivate::isConnected(const char *signalName)
+{
+ return isSignalConnected(signalIndex(signalName));
+}
+
+QSGKeysAttached::QSGKeysAttached(QObject *parent)
+: QObject(*(new QSGKeysAttachedPrivate), parent),
+ QSGItemKeyFilter(qobject_cast<QSGItem*>(parent))
+{
+ Q_D(QSGKeysAttached);
+ m_processPost = false;
+ d->item = qobject_cast<QSGItem*>(parent);
+}
+
+QSGKeysAttached::~QSGKeysAttached()
+{
+}
+
+QSGKeysAttached::Priority QSGKeysAttached::priority() const
+{
+ return m_processPost ? AfterItem : BeforeItem;
+}
+
+void QSGKeysAttached::setPriority(Priority order)
+{
+ bool processPost = order == AfterItem;
+ if (processPost != m_processPost) {
+ m_processPost = processPost;
+ emit priorityChanged();
+ }
+}
+
+void QSGKeysAttached::componentComplete()
+{
+ Q_D(QSGKeysAttached);
+ if (d->item) {
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QSGItem *targetItem = d->targets.at(ii);
+ if (targetItem && (targetItem->flags() & QSGItem::ItemAcceptsInputMethod)) {
+ d->item->setFlag(QSGItem::ItemAcceptsInputMethod);
+ break;
+ }
+ }
+ }
+}
+
+void QSGKeysAttached::keyPressed(QKeyEvent *event, bool post)
+{
+ Q_D(QSGKeysAttached);
+ if (post != m_processPost || !d->enabled || d->inPress) {
+ event->ignore();
+ QSGItemKeyFilter::keyPressed(event, post);
+ return;
+ }
+
+ // first process forwards
+ if (d->item && d->item->canvas()) {
+ d->inPress = true;
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QSGItem *i = d->targets.at(ii);
+ if (i && i->isVisible()) {
+ d->item->canvas()->sendEvent(i, event);
+ if (event->isAccepted()) {
+ d->inPress = false;
+ return;
+ }
+ }
+ }
+ d->inPress = false;
+ }
+
+ QSGKeyEvent ke(*event);
+ QByteArray keySignal = keyToSignal(event->key());
+ if (!keySignal.isEmpty()) {
+ keySignal += "(QSGKeyEvent*)";
+ if (d->isConnected(keySignal)) {
+ // If we specifically handle a key then default to accepted
+ ke.setAccepted(true);
+ int idx = QSGKeysAttached::staticMetaObject.indexOfSignal(keySignal);
+ metaObject()->method(idx).invoke(this, Qt::DirectConnection, Q_ARG(QSGKeyEvent*, &ke));
+ }
+ }
+ if (!ke.isAccepted())
+ emit pressed(&ke);
+ event->setAccepted(ke.isAccepted());
+
+ if (!event->isAccepted()) QSGItemKeyFilter::keyPressed(event, post);
+}
+
+void QSGKeysAttached::keyReleased(QKeyEvent *event, bool post)
+{
+ Q_D(QSGKeysAttached);
+ if (post != m_processPost || !d->enabled || d->inRelease) {
+ event->ignore();
+ QSGItemKeyFilter::keyReleased(event, post);
+ return;
+ }
+
+ if (d->item && d->item->canvas()) {
+ d->inRelease = true;
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QSGItem *i = d->targets.at(ii);
+ if (i && i->isVisible()) {
+ d->item->canvas()->sendEvent(i, event);
+ if (event->isAccepted()) {
+ d->inRelease = false;
+ return;
+ }
+ }
+ }
+ d->inRelease = false;
+ }
+
+ QSGKeyEvent ke(*event);
+ emit released(&ke);
+ event->setAccepted(ke.isAccepted());
+
+ if (!event->isAccepted()) QSGItemKeyFilter::keyReleased(event, post);
+}
+
+void QSGKeysAttached::inputMethodEvent(QInputMethodEvent *event, bool post)
+{
+ Q_D(QSGKeysAttached);
+ if (post == m_processPost && d->item && !d->inIM && d->item->canvas()) {
+ d->inIM = true;
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QSGItem *i = d->targets.at(ii);
+ if (i && i->isVisible() && (i->flags() & QSGItem::ItemAcceptsInputMethod)) {
+ d->item->canvas()->sendEvent(i, event);
+ if (event->isAccepted()) {
+ d->imeItem = i;
+ d->inIM = false;
+ return;
+ }
+ }
+ }
+ d->inIM = false;
+ }
+ QSGItemKeyFilter::inputMethodEvent(event, post);
+}
+
+QVariant QSGKeysAttached::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QSGKeysAttached);
+ if (d->item) {
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QSGItem *i = d->targets.at(ii);
+ if (i && i->isVisible() && (i->flags() & QSGItem::ItemAcceptsInputMethod) && i == d->imeItem) {
+ //### how robust is i == d->imeItem check?
+ QVariant v = i->inputMethodQuery(query);
+ if (v.userType() == QVariant::RectF)
+ v = d->item->mapRectFromItem(i, v.toRectF()); //### cost?
+ return v;
+ }
+ }
+ }
+ return QSGItemKeyFilter::inputMethodQuery(query);
+}
+
+QSGKeysAttached *QSGKeysAttached::qmlAttachedProperties(QObject *obj)
+{
+ return new QSGKeysAttached(obj);
+}
+
+
+QSGLayoutMirroringAttached::QSGLayoutMirroringAttached(QObject *parent) : QObject(parent), itemPrivate(0)
+{
+ if (QSGItem *item = qobject_cast<QSGItem*>(parent)) {
+ itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->attachedLayoutDirection = this;
+ } else
+ qmlInfo(parent) << tr("LayoutDirection attached property only works with Items");
+}
+
+QSGLayoutMirroringAttached * QSGLayoutMirroringAttached::qmlAttachedProperties(QObject *object)
+{
+ return new QSGLayoutMirroringAttached(object);
+}
+
+bool QSGLayoutMirroringAttached::enabled() const
+{
+ return itemPrivate ? itemPrivate->effectiveLayoutMirror : false;
+}
+
+void QSGLayoutMirroringAttached::setEnabled(bool enabled)
+{
+ if (!itemPrivate)
+ return;
+
+ itemPrivate->isMirrorImplicit = false;
+ if (enabled != itemPrivate->effectiveLayoutMirror) {
+ itemPrivate->setLayoutMirror(enabled);
+ if (itemPrivate->inheritMirrorFromItem)
+ itemPrivate->resolveLayoutMirror();
+ }
+}
+
+void QSGLayoutMirroringAttached::resetEnabled()
+{
+ if (itemPrivate && !itemPrivate->isMirrorImplicit) {
+ itemPrivate->isMirrorImplicit = true;
+ itemPrivate->resolveLayoutMirror();
+ }
+}
+
+bool QSGLayoutMirroringAttached::childrenInherit() const
+{
+ return itemPrivate ? itemPrivate->inheritMirrorFromItem : false;
+}
+
+void QSGLayoutMirroringAttached::setChildrenInherit(bool childrenInherit) {
+ if (itemPrivate && childrenInherit != itemPrivate->inheritMirrorFromItem) {
+ itemPrivate->inheritMirrorFromItem = childrenInherit;
+ itemPrivate->resolveLayoutMirror();
+ childrenInheritChanged();
+ }
+}
+
+void QSGItemPrivate::resolveLayoutMirror()
+{
+ Q_Q(QSGItem);
+ if (QSGItem *parentItem = q->parentItem()) {
+ QSGItemPrivate *parentPrivate = QSGItemPrivate::get(parentItem);
+ setImplicitLayoutMirror(parentPrivate->inheritedLayoutMirror, parentPrivate->inheritMirrorFromParent);
+ } else {
+ setImplicitLayoutMirror(isMirrorImplicit ? false : effectiveLayoutMirror, inheritMirrorFromItem);
+ }
+}
+
+void QSGItemPrivate::setImplicitLayoutMirror(bool mirror, bool inherit)
+{
+ inherit = inherit || inheritMirrorFromItem;
+ if (!isMirrorImplicit && inheritMirrorFromItem)
+ mirror = effectiveLayoutMirror;
+ if (mirror == inheritedLayoutMirror && inherit == inheritMirrorFromParent)
+ return;
+
+ inheritMirrorFromParent = inherit;
+ inheritedLayoutMirror = inheritMirrorFromParent ? mirror : false;
+
+ if (isMirrorImplicit)
+ setLayoutMirror(inherit ? inheritedLayoutMirror : false);
+ for (int i = 0; i < childItems.count(); ++i) {
+ if (QSGItem *child = qobject_cast<QSGItem *>(childItems.at(i))) {
+ QSGItemPrivate *childPrivate = QSGItemPrivate::get(child);
+ childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent);
+ }
+ }
+}
+
+void QSGItemPrivate::setLayoutMirror(bool mirror)
+{
+ if (mirror != effectiveLayoutMirror) {
+ effectiveLayoutMirror = mirror;
+ if (_anchors) {
+ QSGAnchorsPrivate *anchor_d = QSGAnchorsPrivate::get(_anchors);
+ anchor_d->fillChanged();
+ anchor_d->centerInChanged();
+ anchor_d->updateHorizontalAnchors();
+ emit _anchors->mirroredChanged();
+ }
+ mirrorChange();
+ if (attachedLayoutDirection) {
+ emit attachedLayoutDirection->enabledChanged();
+ }
+ }
+}
+
+QSGItem::QSGItem(QSGItem* parent)
+: QObject(*(new QSGItemPrivate), parent)
+{
+ Q_D(QSGItem);
+ d->init(parent);
+}
+
+QSGItem::QSGItem(QSGItemPrivate &dd, QSGItem *parent)
+: QObject(dd, parent)
+{
+ Q_D(QSGItem);
+ d->init(parent);
+}
+
+QSGItem::~QSGItem()
+{
+ Q_D(QSGItem);
+
+ // XXX todo - optimize
+ setParentItem(0);
+ while (!d->childItems.isEmpty())
+ d->childItems.first()->setParentItem(0);
+
+ for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ QSGAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
+ if (anchor)
+ anchor->clearItem(this);
+ }
+
+ // XXX todo - the original checks if the parent is being destroyed
+ for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ QSGAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
+ if (anchor && anchor->item && anchor->item->parent() != this) //child will be deleted anyway
+ anchor->updateOnComplete();
+ }
+
+ for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Destroyed)
+ change.listener->itemDestroyed(this);
+ }
+ d->changeListeners.clear();
+ delete d->_anchorLines; d->_anchorLines = 0;
+ delete d->_anchors; d->_anchors = 0;
+ delete d->_stateGroup; d->_stateGroup = 0;
+ delete d->_contents; d->_contents = 0;
+}
+
+void QSGItem::setParentItem(QSGItem *parentItem)
+{
+ Q_D(QSGItem);
+ if (parentItem == d->parentItem)
+ return;
+
+ d->removeFromDirtyList();
+
+ QSGItem *oldParentItem = d->parentItem;
+ QSGItem *scopeFocusedItem = 0;
+
+ if (oldParentItem) {
+ QSGItemPrivate *op = QSGItemPrivate::get(oldParentItem);
+
+ QSGItem *scopeItem = 0;
+
+ if (d->canvas && hasFocus()) {
+ scopeItem = oldParentItem;
+ while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+ scopeFocusedItem = this;
+ } else if (d->canvas && !isFocusScope() && d->subFocusItem) {
+ scopeItem = oldParentItem;
+ while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+ scopeFocusedItem = d->subFocusItem;
+ }
+
+ if (scopeFocusedItem)
+ QSGCanvasPrivate::get(d->canvas)->clearFocusInScope(scopeItem, scopeFocusedItem,
+ QSGCanvasPrivate::DontChangeFocusProperty);
+
+ op->removeChild(this);
+ }
+
+ d->parentItem = parentItem;
+
+ QSGCanvas *parentCanvas = parentItem?QSGItemPrivate::get(parentItem)->canvas:0;
+ if (d->canvas != parentCanvas) {
+ if (d->canvas && d->itemNodeInstance)
+ QSGCanvasPrivate::get(d->canvas)->cleanup(d->itemNodeInstance);
+
+ QSGItemPrivate::InitializationState initState;
+ initState.clear();
+ d->initCanvas(&initState, parentCanvas);
+ }
+
+ d->dirty(QSGItemPrivate::ParentChanged);
+
+ if (d->parentItem)
+ QSGItemPrivate::get(d->parentItem)->addChild(this);
+
+ d->setEffectiveVisibleRecur(d->calcEffectiveVisible());
+ d->setEffectiveEnableRecur(d->calcEffectiveEnable());
+
+ if (scopeFocusedItem && d->parentItem && d->canvas) {
+ // We need to test whether this item becomes scope focused
+ QSGItem *scopeItem = 0;
+ scopeItem = d->parentItem;
+ while (!scopeItem->isFocusScope()) scopeItem = scopeItem->parentItem();
+
+ if (scopeItem->scopedFocusItem()) {
+ QSGItemPrivate::get(scopeFocusedItem)->focus = false;
+ emit scopeFocusedItem->focusChanged(false);
+ } else {
+ QSGCanvasPrivate::get(d->canvas)->setFocusInScope(scopeItem, scopeFocusedItem,
+ QSGCanvasPrivate::DontChangeFocusProperty);
+ }
+ }
+
+ d->resolveLayoutMirror();
+
+ d->itemChange(ItemParentHasChanged, d->parentItem);
+
+ emit parentChanged(d->parentItem);
+}
+
+void QSGItem::stackBefore(const QSGItem *sibling)
+{
+ Q_D(QSGItem);
+ if (!sibling || sibling == this || !d->parentItem || d->parentItem != QSGItemPrivate::get(sibling)->parentItem) {
+ qWarning("QSGItem::stackBefore: Cannot stack before %p, which must be a sibling", sibling);
+ return;
+ }
+
+ QSGItemPrivate *parentPrivate = QSGItemPrivate::get(d->parentItem);
+
+ int myIndex = parentPrivate->childItems.indexOf(this);
+ int siblingIndex = parentPrivate->childItems.indexOf(const_cast<QSGItem *>(sibling));
+
+ Q_ASSERT(myIndex != -1 && siblingIndex != -1);
+
+ if (myIndex == siblingIndex - 1)
+ return;
+
+ parentPrivate->childItems.removeAt(myIndex);
+
+ if (myIndex < siblingIndex) --siblingIndex;
+
+ parentPrivate->childItems.insert(siblingIndex, this);
+
+ parentPrivate->dirty(QSGItemPrivate::ChildrenStackingChanged);
+
+ for (int ii = qMin(siblingIndex, myIndex); ii < parentPrivate->childItems.count(); ++ii)
+ QSGItemPrivate::get(parentPrivate->childItems.at(ii))->siblingOrderChanged();
+}
+
+void QSGItem::stackAfter(const QSGItem *sibling)
+{
+ Q_D(QSGItem);
+ if (!sibling || sibling == this || !d->parentItem || d->parentItem != QSGItemPrivate::get(sibling)->parentItem) {
+ qWarning("QSGItem::stackAfter: Cannot stack after %p, which must be a sibling", sibling);
+ return;
+ }
+
+ QSGItemPrivate *parentPrivate = QSGItemPrivate::get(d->parentItem);
+
+ int myIndex = parentPrivate->childItems.indexOf(this);
+ int siblingIndex = parentPrivate->childItems.indexOf(const_cast<QSGItem *>(sibling));
+
+ Q_ASSERT(myIndex != -1 && siblingIndex != -1);
+
+ if (myIndex == siblingIndex + 1)
+ return;
+
+ parentPrivate->childItems.removeAt(myIndex);
+
+ if (myIndex < siblingIndex) --siblingIndex;
+
+ parentPrivate->childItems.insert(siblingIndex + 1, this);
+
+ parentPrivate->dirty(QSGItemPrivate::ChildrenStackingChanged);
+
+ for (int ii = qMin(myIndex, siblingIndex + 1); ii < parentPrivate->childItems.count(); ++ii)
+ QSGItemPrivate::get(parentPrivate->childItems.at(ii))->siblingOrderChanged();
+}
+
+/*!
+ Returns the QSGItem parent of this item.
+*/
+QSGItem *QSGItem::parentItem() const
+{
+ Q_D(const QSGItem);
+ return d->parentItem;
+}
+
+QSGEngine *QSGItem::sceneGraphEngine() const
+{
+ return canvas()->sceneGraphEngine();
+}
+
+QSGCanvas *QSGItem::canvas() const
+{
+ Q_D(const QSGItem);
+ return d->canvas;
+}
+
+static bool itemZOrder_sort(QSGItem *lhs, QSGItem *rhs)
+{
+ return lhs->z() < rhs->z();
+}
+
+QList<QSGItem *> QSGItemPrivate::paintOrderChildItems() const
+{
+ // XXX todo - optimize, don't sort and return items that are
+ // ignored anyway, like invisible or disabled items.
+ QList<QSGItem *> items = childItems;
+ qStableSort(items.begin(), items.end(), itemZOrder_sort);
+ return items;
+}
+
+void QSGItemPrivate::addChild(QSGItem *child)
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(!childItems.contains(child));
+
+ childItems.append(child);
+
+ dirty(QSGItemPrivate::ChildrenChanged);
+
+ itemChange(QSGItem::ItemChildAddedChange, child);
+
+ emit q->childrenChanged();
+}
+
+void QSGItemPrivate::removeChild(QSGItem *child)
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(child);
+ Q_ASSERT(childItems.contains(child));
+ childItems.removeOne(child);
+ Q_ASSERT(!childItems.contains(child));
+
+ dirty(QSGItemPrivate::ChildrenChanged);
+
+ itemChange(QSGItem::ItemChildRemovedChange, child);
+
+ emit q->childrenChanged();
+}
+
+void QSGItemPrivate::InitializationState::clear()
+{
+ focusScope = 0;
+}
+
+void QSGItemPrivate::InitializationState::clear(QSGItem *fs)
+{
+ focusScope = fs;
+}
+
+QSGItem *QSGItemPrivate::InitializationState::getFocusScope(QSGItem *item)
+{
+ if (!focusScope) {
+ QSGItem *fs = item->parentItem();
+ while (!fs->isFocusScope())
+ fs = fs->parentItem();
+ focusScope = fs;
+ }
+ return focusScope;
+}
+
+void QSGItemPrivate::initCanvas(InitializationState *state, QSGCanvas *c)
+{
+ Q_Q(QSGItem);
+
+ if (canvas) {
+ removeFromDirtyList();
+ QSGCanvasPrivate *c = QSGCanvasPrivate::get(canvas);
+ if (polishScheduled)
+ c->itemsToPolish.remove(q);
+ if (c->mouseGrabberItem == q)
+ c->mouseGrabberItem = 0;
+ }
+
+ canvas = c;
+
+ if (canvas && polishScheduled)
+ QSGCanvasPrivate::get(canvas)->itemsToPolish.insert(q);
+
+ if (canvas && hoverEnabled && !canvas->hasMouseTracking())
+ canvas->setMouseTracking(true);
+
+ // XXX todo - why aren't these added to the destroy list?
+ itemNodeInstance = 0;
+ opacityNode = 0;
+ clipNode = 0;
+ rootNode = 0;
+ groupNode = 0;
+ paintNode = 0;
+ paintNodeIndex = 0;
+
+ InitializationState _dummy;
+ InitializationState *childState = state;
+
+ if (c && q->isFocusScope()) {
+ _dummy.clear(q);
+ childState = &_dummy;
+ }
+
+ for (int ii = 0; ii < childItems.count(); ++ii) {
+ QSGItem *child = childItems.at(ii);
+ QSGItemPrivate::get(child)->initCanvas(childState, c);
+ }
+
+ if (c && focus) {
+ // Fixup
+ if (state->getFocusScope(q)->scopedFocusItem()) {
+ focus = false;
+ emit q->focusChanged(false);
+ } else {
+ QSGCanvasPrivate::get(canvas)->setFocusInScope(state->getFocusScope(q), q);
+ }
+ }
+
+ dirty(Canvas);
+
+ itemChange(QSGItem::ItemSceneChange, c);
+}
+
+/*!
+Returns a transform that maps points from canvas space into item space.
+*/
+QTransform QSGItemPrivate::canvasToItemTransform() const
+{
+ // XXX todo - optimize
+ return itemToCanvasTransform().inverted();
+}
+
+/*!
+Returns a transform that maps points from item space into canvas space.
+*/
+QTransform QSGItemPrivate::itemToCanvasTransform() const
+{
+ // XXX todo
+ QTransform rv = parentItem?QSGItemPrivate::get(parentItem)->itemToCanvasTransform():QTransform();
+ itemToParentTransform(rv);
+ return rv;
+}
+
+/*!
+Motifies \a t with this items local transform relative to its parent.
+*/
+void QSGItemPrivate::itemToParentTransform(QTransform &t) const
+{
+ if (x || y)
+ t.translate(x, y);
+
+ if (!transforms.isEmpty()) {
+ QMatrix4x4 m(t);
+ for (int ii = transforms.count() - 1; ii >= 0; --ii)
+ transforms.at(ii)->applyTo(&m);
+ t = m.toTransform();
+ }
+
+ if (scale != 1. || rotation != 0.) {
+ QPointF tp = computeTransformOrigin();
+ t.translate(tp.x(), tp.y());
+ t.scale(scale, scale);
+ t.rotate(rotation);
+ t.translate(-tp.x(), -tp.y());
+ }
+}
+
+bool QSGItem::isComponentComplete() const
+{
+ Q_D(const QSGItem);
+ return d->componentComplete;
+}
+
+QSGItemPrivate::QSGItemPrivate()
+: _anchors(0), _contents(0), baselineOffset(0), _anchorLines(0), _stateGroup(0), origin(QSGItem::Center),
+
+ flags(0), widthValid(false), heightValid(false), componentComplete(true),
+ keepMouse(false), hoverEnabled(false), smooth(false), focus(false), activeFocus(false), notifiedFocus(false),
+ notifiedActiveFocus(false), filtersChildMouseEvents(false), explicitVisible(true),
+ effectiveVisible(true), explicitEnable(true), effectiveEnable(true), polishScheduled(false),
+ inheritedLayoutMirror(false), effectiveLayoutMirror(false), isMirrorImplicit(true),
+ inheritMirrorFromParent(false), inheritMirrorFromItem(false),
+
+ canvas(0), parentItem(0),
+
+ subFocusItem(0),
+
+ x(0), y(0), width(0), height(0), implicitWidth(0), implicitHeight(0),
+ z(0), scale(1), rotation(0), opacity(1),
+
+ attachedLayoutDirection(0), acceptedMouseButtons(0),
+ imHints(Qt::ImhNone),
+
+ keyHandler(0),
+
+ dirtyAttributes(0), nextDirtyItem(0), prevDirtyItem(0),
+
+ itemNodeInstance(0), opacityNode(0), clipNode(0), rootNode(0), groupNode(0), paintNode(0)
+ , paintNodeIndex(0), effectRefCount(0), hideRefCount(0)
+{
+}
+
+void QSGItemPrivate::init(QSGItem *parent)
+{
+ Q_Q(QSGItem);
+ baselineOffset.invalidate();
+
+ if (parent) {
+ q->setParentItem(parent);
+ QSGItemPrivate *parentPrivate = QSGItemPrivate::get(parent);
+ setImplicitLayoutMirror(parentPrivate->inheritedLayoutMirror, parentPrivate->inheritMirrorFromParent);
+ }
+}
+
+void QSGItemPrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
+{
+ if (!o)
+ return;
+
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+
+ // This test is measurably (albeit only slightly) faster than qobject_cast<>()
+ const QMetaObject *mo = o->metaObject();
+ while (mo && mo != &QSGItem::staticMetaObject) {
+ if (mo == &QDeclarativeItem::staticMetaObject)
+ qWarning("Cannot add a QtQuick 1.0 item (%s) into a QtQuick 2.0 scene!", o->metaObject()->className());
+ mo = mo->d.superdata;
+ }
+
+ if (mo) {
+ QSGItem *item = static_cast<QSGItem *>(o);
+ item->setParentItem(that);
+ } else {
+ // XXX todo - do we really want this behavior?
+ o->setParent(that);
+ }
+}
+
+int QSGItemPrivate::data_count(QDeclarativeListProperty<QObject> *prop)
+{
+ Q_UNUSED(prop);
+ // XXX todo
+ return 0;
+}
+
+QObject *QSGItemPrivate::data_at(QDeclarativeListProperty<QObject> *prop, int i)
+{
+ Q_UNUSED(prop);
+ Q_UNUSED(i);
+ // XXX todo
+ return 0;
+}
+
+void QSGItemPrivate::data_clear(QDeclarativeListProperty<QObject> *prop)
+{
+ Q_UNUSED(prop);
+ // XXX todo
+}
+
+QObject *QSGItemPrivate::resources_at(QDeclarativeListProperty<QObject> *prop, int index)
+{
+ const QObjectList children = prop->object->children();
+ if (index < children.count())
+ return children.at(index);
+ else
+ return 0;
+}
+
+void QSGItemPrivate::resources_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
+{
+ // XXX todo - do we really want this behavior?
+ o->setParent(prop->object);
+}
+
+int QSGItemPrivate::resources_count(QDeclarativeListProperty<QObject> *prop)
+{
+ return prop->object->children().count();
+}
+
+void QSGItemPrivate::resources_clear(QDeclarativeListProperty<QObject> *prop)
+{
+ // XXX todo - do we really want this behavior?
+ const QObjectList children = prop->object->children();
+ for (int index = 0; index < children.count(); index++)
+ children.at(index)->setParent(0);
+}
+
+QSGItem *QSGItemPrivate::children_at(QDeclarativeListProperty<QSGItem> *prop, int index)
+{
+ QSGItemPrivate *p = QSGItemPrivate::get(static_cast<QSGItem *>(prop->object));
+ if (index >= p->childItems.count() || index < 0)
+ return 0;
+ else
+ return p->childItems.at(index);
+}
+
+void QSGItemPrivate::children_append(QDeclarativeListProperty<QSGItem> *prop, QSGItem *o)
+{
+ if (!o)
+ return;
+
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ if (o->parentItem() == that)
+ o->setParentItem(0);
+
+ o->setParentItem(that);
+}
+
+int QSGItemPrivate::children_count(QDeclarativeListProperty<QSGItem> *prop)
+{
+ QSGItemPrivate *p = QSGItemPrivate::get(static_cast<QSGItem *>(prop->object));
+ return p->childItems.count();
+}
+
+void QSGItemPrivate::children_clear(QDeclarativeListProperty<QSGItem> *prop)
+{
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ QSGItemPrivate *p = QSGItemPrivate::get(that);
+ while (!p->childItems.isEmpty())
+ p->childItems.at(0)->setParentItem(0);
+}
+
+int QSGItemPrivate::transform_count(QDeclarativeListProperty<QSGTransform> *prop)
+{
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ return QSGItemPrivate::get(that)->transforms.count();
+}
+
+void QSGTransform::appendToItem(QSGItem *item)
+{
+ Q_D(QSGTransform);
+ if (!item)
+ return;
+
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+
+ if (!d->items.isEmpty() && !p->transforms.isEmpty() && p->transforms.contains(this)) {
+ p->transforms.removeOne(this);
+ p->transforms.append(this);
+ } else {
+ p->transforms.append(this);
+ d->items.append(item);
+ }
+
+ p->dirty(QSGItemPrivate::Transform);
+}
+
+void QSGTransform::prependToItem(QSGItem *item)
+{
+ Q_D(QSGTransform);
+ if (!item)
+ return;
+
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+
+ if (!d->items.isEmpty() && !p->transforms.isEmpty() && p->transforms.contains(this)) {
+ p->transforms.removeOne(this);
+ p->transforms.prepend(this);
+ } else {
+ p->transforms.prepend(this);
+ d->items.append(item);
+ }
+
+ p->dirty(QSGItemPrivate::Transform);
+}
+
+void QSGItemPrivate::transform_append(QDeclarativeListProperty<QSGTransform> *prop, QSGTransform *transform)
+{
+ if (!transform)
+ return;
+
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ transform->appendToItem(that);
+}
+
+QSGTransform *QSGItemPrivate::transform_at(QDeclarativeListProperty<QSGTransform> *prop, int idx)
+{
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ QSGItemPrivate *p = QSGItemPrivate::get(that);
+
+ if (idx < 0 || idx >= p->transforms.count())
+ return 0;
+ else
+ return p->transforms.at(idx);
+}
+
+void QSGItemPrivate::transform_clear(QDeclarativeListProperty<QSGTransform> *prop)
+{
+ QSGItem *that = static_cast<QSGItem *>(prop->object);
+ QSGItemPrivate *p = QSGItemPrivate::get(that);
+
+ for (int ii = 0; ii < p->transforms.count(); ++ii) {
+ QSGTransform *t = p->transforms.at(ii);
+ QSGTransformPrivate *tp = QSGTransformPrivate::get(t);
+ tp->items.removeOne(that);
+ }
+
+ p->transforms.clear();
+
+ p->dirty(QSGItemPrivate::Transform);
+}
+
+QSGAnchors *QSGItemPrivate::anchors() const
+{
+ if (!_anchors) {
+ Q_Q(const QSGItem);
+ _anchors = new QSGAnchors(const_cast<QSGItem *>(q));
+ if (!componentComplete)
+ _anchors->classBegin();
+ }
+ return _anchors;
+}
+
+QSGItemPrivate::AnchorLines *QSGItemPrivate::anchorLines() const
+{
+ Q_Q(const QSGItem);
+ if (!_anchorLines) _anchorLines =
+ new AnchorLines(const_cast<QSGItem *>(q));
+ return _anchorLines;
+}
+
+void QSGItemPrivate::siblingOrderChanged()
+{
+ Q_Q(QSGItem);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::SiblingOrder) {
+ change.listener->itemSiblingOrderChanged(q);
+ }
+ }
+}
+
+QDeclarativeListProperty<QObject> QSGItemPrivate::data()
+{
+ return QDeclarativeListProperty<QObject>(q_func(), 0, QSGItemPrivate::data_append,
+ QSGItemPrivate::data_count,
+ QSGItemPrivate::data_at,
+ QSGItemPrivate::data_clear);
+}
+
+QRectF QSGItem::childrenRect()
+{
+ Q_D(QSGItem);
+ if (!d->_contents) {
+ d->_contents = new QSGContents(this);
+ if (d->componentComplete)
+ d->_contents->complete();
+ }
+ return d->_contents->rectF();
+}
+
+QList<QSGItem *> QSGItem::childItems() const
+{
+ Q_D(const QSGItem);
+ return d->childItems;
+}
+
+bool QSGItem::clip() const
+{
+ return flags() & ItemClipsChildrenToShape;
+}
+
+void QSGItem::setClip(bool c)
+{
+ if (clip() == c)
+ return;
+
+ setFlag(ItemClipsChildrenToShape, c);
+
+ emit clipChanged(c);
+}
+
+void QSGItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QSGItem);
+
+ if (d->_anchors)
+ QSGAnchorsPrivate::get(d->_anchors)->updateMe();
+
+ for(int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Geometry)
+ change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
+ }
+
+ if (newGeometry.x() != oldGeometry.x())
+ emit xChanged();
+ if (newGeometry.y() != oldGeometry.y())
+ emit yChanged();
+ if (newGeometry.width() != oldGeometry.width())
+ emit widthChanged();
+ if (newGeometry.height() != oldGeometry.height())
+ emit heightChanged();
+}
+
+/*!
+ Called by the rendering thread when it is time to sync the state of the QML objects with the
+ scene graph objects. The function should return the root of the scene graph subtree for
+ this item. \a oldNode is the node that was returned the last time the function was called.
+
+ The main thread is blocked while this function is executed so it is safe to read
+ values from the QSGItem instance and other objects in the main thread.
+
+ \warning This is the only function in which it is allowed to make use of scene graph
+ objects from the main thread. Use of scene graph objects outside this function will
+ result in race conditions and potential crashes.
+ */
+
+QSGNode *QSGItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ delete oldNode;
+ return 0;
+}
+
+QSGTransformNode *QSGItemPrivate::createTransformNode()
+{
+ return new QSGTransformNode;
+}
+
+void QSGItem::updatePolish()
+{
+}
+
+void QSGItemPrivate::removeItemChangeListener(QSGItemChangeListener *listener, ChangeTypes types)
+{
+ ChangeListener change(listener, types);
+ changeListeners.removeOne(change);
+}
+
+void QSGItem::keyPressEvent(QKeyEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::keyReleaseEvent(QKeyEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::inputMethodEvent(QInputMethodEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::focusInEvent(QFocusEvent *)
+{
+}
+
+void QSGItem::focusOutEvent(QFocusEvent *)
+{
+}
+
+void QSGItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ mousePressEvent(event);
+}
+
+void QSGItem::mouseUngrabEvent()
+{
+ // XXX todo
+}
+
+void QSGItem::wheelEvent(QGraphicsSceneWheelEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::touchEvent(QTouchEvent *event)
+{
+ event->ignore();
+}
+
+void QSGItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+void QSGItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+void QSGItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+bool QSGItem::childMouseEventFilter(QSGItem *, QEvent *)
+{
+ return false;
+}
+
+Qt::InputMethodHints QSGItem::inputMethodHints() const
+{
+ Q_D(const QSGItem);
+ return d->imHints;
+}
+
+void QSGItem::setInputMethodHints(Qt::InputMethodHints hints)
+{
+ Q_D(QSGItem);
+ d->imHints = hints;
+
+ if (!d->canvas || d->canvas->activeFocusItem() != this)
+ return;
+
+ QSGCanvasPrivate::get(d->canvas)->updateInputMethodData();
+#ifndef QT_NO_IM
+ if (d->canvas->hasFocus())
+ if (QInputContext *inputContext = d->canvas->inputContext())
+ inputContext->update();
+#endif
+}
+
+void QSGItem::updateMicroFocus()
+{
+#ifndef QT_NO_IM
+ Q_D(QSGItem);
+ if (d->canvas && d->canvas->hasFocus())
+ if (QInputContext *inputContext = d->canvas->inputContext())
+ inputContext->update();
+#endif
+}
+
+QVariant QSGItem::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QSGItem);
+ QVariant v;
+
+ if (d->keyHandler)
+ v = d->keyHandler->inputMethodQuery(query);
+
+ return v;
+}
+
+QSGAnchorLine QSGItemPrivate::left() const
+{
+ return anchorLines()->left;
+}
+
+QSGAnchorLine QSGItemPrivate::right() const
+{
+ return anchorLines()->right;
+}
+
+QSGAnchorLine QSGItemPrivate::horizontalCenter() const
+{
+ return anchorLines()->hCenter;
+}
+
+QSGAnchorLine QSGItemPrivate::top() const
+{
+ return anchorLines()->top;
+}
+
+QSGAnchorLine QSGItemPrivate::bottom() const
+{
+ return anchorLines()->bottom;
+}
+
+QSGAnchorLine QSGItemPrivate::verticalCenter() const
+{
+ return anchorLines()->vCenter;
+}
+
+QSGAnchorLine QSGItemPrivate::baseline() const
+{
+ return anchorLines()->baseline;
+}
+
+qreal QSGItem::baselineOffset() const
+{
+ Q_D(const QSGItem);
+ if (!d->baselineOffset.isValid()) {
+ return 0.0;
+ } else
+ return d->baselineOffset;
+}
+
+void QSGItem::setBaselineOffset(qreal offset)
+{
+ Q_D(QSGItem);
+ if (offset == d->baselineOffset)
+ return;
+
+ d->baselineOffset = offset;
+
+ for(int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Geometry) {
+ QSGAnchorsPrivate *anchor = change.listener->anchorPrivate();
+ if (anchor)
+ anchor->updateVerticalAnchors();
+ }
+ }
+ emit baselineOffsetChanged(offset);
+}
+
+void QSGItem::update()
+{
+ Q_D(QSGItem);
+ Q_ASSERT(flags() & ItemHasContents);
+ d->dirty(QSGItemPrivate::Content);
+}
+
+void QSGItem::polish()
+{
+ Q_D(QSGItem);
+ if (!d->polishScheduled) {
+ d->polishScheduled = true;
+ if (d->canvas)
+ QSGCanvasPrivate::get(d->canvas)->itemsToPolish.insert(this);
+ }
+}
+
+QScriptValue QSGItem::mapFromItem(const QScriptValue &item, qreal x, qreal y) const
+{
+ QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject();
+ QSGItem *itemObj = qobject_cast<QSGItem*>(item.toQObject());
+ if (!itemObj && !item.isNull()) {
+ qmlInfo(this) << "mapFromItem() given argument \"" << item.toString() << "\" which is neither null nor an Item";
+ return 0;
+ }
+
+ // If QSGItem::mapFromItem() is called with 0, behaves the same as mapFromScene()
+ QPointF p = mapFromItem(itemObj, QPointF(x, y));
+ sv.setProperty(QLatin1String("x"), p.x());
+ sv.setProperty(QLatin1String("y"), p.y());
+ return sv;
+}
+
+QTransform QSGItem::itemTransform(QSGItem *other, bool *ok) const
+{
+ Q_D(const QSGItem);
+
+ // XXX todo - we need to be able to handle common parents better and detect
+ // invalid cases
+ if (ok) *ok = true;
+
+ QTransform t = d->itemToCanvasTransform();
+ if (other) t *= QSGItemPrivate::get(other)->canvasToItemTransform();
+
+ return t;
+}
+
+QScriptValue QSGItem::mapToItem(const QScriptValue &item, qreal x, qreal y) const
+{
+ QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject();
+ QSGItem *itemObj = qobject_cast<QSGItem*>(item.toQObject());
+ if (!itemObj && !item.isNull()) {
+ qmlInfo(this) << "mapToItem() given argument \"" << item.toString() << "\" which is neither null nor an Item";
+ return 0;
+ }
+
+ // If QSGItem::mapToItem() is called with 0, behaves the same as mapToScene()
+ QPointF p = mapToItem(itemObj, QPointF(x, y));
+ sv.setProperty(QLatin1String("x"), p.x());
+ sv.setProperty(QLatin1String("y"), p.y());
+ return sv;
+}
+
+void QSGItem::forceActiveFocus()
+{
+ setFocus(true);
+ QSGItem *parent = parentItem();
+ while (parent) {
+ if (parent->flags() & QSGItem::ItemIsFocusScope) {
+ parent->setFocus(true);
+ }
+ parent = parent->parentItem();
+ }
+}
+
+QSGItem *QSGItem::childAt(qreal x, qreal y) const
+{
+ // XXX todo - should this include transform etc.?
+ const QList<QSGItem *> children = childItems();
+ for (int i = children.count()-1; i >= 0; --i) {
+ if (QSGItem *child = qobject_cast<QSGItem *>(children.at(i))) {
+ if (child->isVisible() && child->x() <= x
+ && child->x() + child->width() >= x
+ && child->y() <= y
+ && child->y() + child->height() >= y)
+ return child;
+ }
+ }
+ return 0;
+}
+
+QDeclarativeListProperty<QObject> QSGItemPrivate::resources()
+{
+ return QDeclarativeListProperty<QObject>(q_func(), 0, QSGItemPrivate::resources_append,
+ QSGItemPrivate::resources_count,
+ QSGItemPrivate::resources_at,
+ QSGItemPrivate::resources_clear);
+}
+
+QDeclarativeListProperty<QSGItem> QSGItemPrivate::children()
+{
+ return QDeclarativeListProperty<QSGItem>(q_func(), 0, QSGItemPrivate::children_append,
+ QSGItemPrivate::children_count,
+ QSGItemPrivate::children_at,
+ QSGItemPrivate::children_clear);
+
+}
+
+QDeclarativeListProperty<QDeclarativeState> QSGItemPrivate::states()
+{
+ return _states()->statesProperty();
+}
+
+QDeclarativeListProperty<QDeclarativeTransition> QSGItemPrivate::transitions()
+{
+ return _states()->transitionsProperty();
+}
+
+QString QSGItemPrivate::state() const
+{
+ if (!_stateGroup)
+ return QString();
+ else
+ return _stateGroup->state();
+}
+
+void QSGItemPrivate::setState(const QString &state)
+{
+ _states()->setState(state);
+}
+
+QDeclarativeListProperty<QSGTransform> QSGItem::transform()
+{
+ Q_D(QSGItem);
+ return QDeclarativeListProperty<QSGTransform>(this, 0, d->transform_append, d->transform_count,
+ d->transform_at, d->transform_clear);
+}
+
+void QSGItem::classBegin()
+{
+ Q_D(QSGItem);
+ d->componentComplete = false;
+ if (d->_stateGroup)
+ d->_stateGroup->classBegin();
+ if (d->_anchors)
+ d->_anchors->classBegin();
+}
+
+void QSGItem::componentComplete()
+{
+ Q_D(QSGItem);
+ d->componentComplete = true;
+ if (d->_stateGroup)
+ d->_stateGroup->componentComplete();
+ if (d->_anchors) {
+ d->_anchors->componentComplete();
+ QSGAnchorsPrivate::get(d->_anchors)->updateOnComplete();
+ }
+ if (d->keyHandler)
+ d->keyHandler->componentComplete();
+ if (d->_contents)
+ d->_contents->complete();
+}
+
+QDeclarativeStateGroup *QSGItemPrivate::_states()
+{
+ Q_Q(QSGItem);
+ if (!_stateGroup) {
+ _stateGroup = new QDeclarativeStateGroup;
+ if (!componentComplete)
+ _stateGroup->classBegin();
+ QObject::connect(_stateGroup, SIGNAL(stateChanged(QString)),
+ q, SIGNAL(stateChanged(QString)));
+ }
+
+ return _stateGroup;
+}
+
+QSGItemPrivate::AnchorLines::AnchorLines(QSGItem *q)
+{
+ left.item = q;
+ left.anchorLine = QSGAnchorLine::Left;
+ right.item = q;
+ right.anchorLine = QSGAnchorLine::Right;
+ hCenter.item = q;
+ hCenter.anchorLine = QSGAnchorLine::HCenter;
+ top.item = q;
+ top.anchorLine = QSGAnchorLine::Top;
+ bottom.item = q;
+ bottom.anchorLine = QSGAnchorLine::Bottom;
+ vCenter.item = q;
+ vCenter.anchorLine = QSGAnchorLine::VCenter;
+ baseline.item = q;
+ baseline.anchorLine = QSGAnchorLine::Baseline;
+}
+
+QPointF QSGItemPrivate::computeTransformOrigin() const
+{
+ switch(origin) {
+ default:
+ case QSGItem::TopLeft:
+ return QPointF(0, 0);
+ case QSGItem::Top:
+ return QPointF(width / 2., 0);
+ case QSGItem::TopRight:
+ return QPointF(width, 0);
+ case QSGItem::Left:
+ return QPointF(0, height / 2.);
+ case QSGItem::Center:
+ return QPointF(width / 2., height / 2.);
+ case QSGItem::Right:
+ return QPointF(width, height / 2.);
+ case QSGItem::BottomLeft:
+ return QPointF(0, height);
+ case QSGItem::Bottom:
+ return QPointF(width / 2., height);
+ case QSGItem::BottomRight:
+ return QPointF(width, height);
+ }
+}
+
+void QSGItemPrivate::transformChanged()
+{
+}
+
+void QSGItemPrivate::deliverKeyEvent(QKeyEvent *e)
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(e->isAccepted());
+ if (keyHandler) {
+ if (e->type() == QEvent::KeyPress)
+ keyHandler->keyPressed(e, false);
+ else
+ keyHandler->keyReleased(e, false);
+
+ if (e->isAccepted())
+ return;
+ else
+ e->accept();
+ }
+
+ if (e->type() == QEvent::KeyPress)
+ q->keyPressEvent(e);
+ else
+ q->keyReleaseEvent(e);
+
+ if (e->isAccepted())
+ return;
+
+ if (keyHandler) {
+ e->accept();
+
+ if (e->type() == QEvent::KeyPress)
+ keyHandler->keyPressed(e, true);
+ else
+ keyHandler->keyReleased(e, true);
+ }
+}
+
+void QSGItemPrivate::deliverInputMethodEvent(QInputMethodEvent *e)
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(e->isAccepted());
+ if (keyHandler) {
+ keyHandler->inputMethodEvent(e, false);
+
+ if (e->isAccepted())
+ return;
+ else
+ e->accept();
+ }
+
+ q->inputMethodEvent(e);
+
+ if (e->isAccepted())
+ return;
+
+ if (keyHandler) {
+ e->accept();
+
+ keyHandler->inputMethodEvent(e, true);
+ }
+}
+
+void QSGItemPrivate::deliverFocusEvent(QFocusEvent *e)
+{
+ Q_Q(QSGItem);
+
+ if (e->type() == QEvent::FocusIn) {
+ q->focusInEvent(e);
+ } else {
+ q->focusOutEvent(e);
+ }
+}
+
+void QSGItemPrivate::deliverMouseEvent(QGraphicsSceneMouseEvent *e)
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(e->isAccepted());
+
+ switch(e->type()) {
+ default:
+ Q_ASSERT(!"Unknown event type");
+ case QEvent::GraphicsSceneMouseMove:
+ q->mouseMoveEvent(e);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ q->mousePressEvent(e);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ q->mouseReleaseEvent(e);
+ break;
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ q->mouseDoubleClickEvent(e);
+ break;
+ }
+}
+
+void QSGItemPrivate::deliverWheelEvent(QGraphicsSceneWheelEvent *e)
+{
+ Q_Q(QSGItem);
+ q->wheelEvent(e);
+}
+
+void QSGItemPrivate::deliverTouchEvent(QTouchEvent *e)
+{
+ Q_Q(QSGItem);
+ q->touchEvent(e);
+}
+
+void QSGItemPrivate::deliverHoverEvent(QGraphicsSceneHoverEvent *e)
+{
+ Q_Q(QSGItem);
+ switch(e->type()) {
+ default:
+ Q_ASSERT(!"Unknown event type");
+ case QEvent::GraphicsSceneHoverEnter:
+ q->hoverEnterEvent(e);
+ break;
+ case QEvent::GraphicsSceneHoverLeave:
+ q->hoverLeaveEvent(e);
+ break;
+ case QEvent::GraphicsSceneHoverMove:
+ q->hoverMoveEvent(e);
+ break;
+ }
+}
+
+void QSGItem::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_UNUSED(change);
+ Q_UNUSED(value);
+}
+
+/*! \internal */
+// XXX todo - do we want/need this anymore?
+QRectF QSGItem::boundingRect() const
+{
+ Q_D(const QSGItem);
+ return QRectF(0, 0, d->width, d->height);
+}
+
+QSGItem::TransformOrigin QSGItem::transformOrigin() const
+{
+ Q_D(const QSGItem);
+ return d->origin;
+}
+
+void QSGItem::setTransformOrigin(TransformOrigin origin)
+{
+ Q_D(QSGItem);
+ if (origin == d->origin)
+ return;
+
+ d->origin = origin;
+ d->dirty(QSGItemPrivate::TransformOrigin);
+
+ emit transformOriginChanged(d->origin);
+}
+
+QPointF QSGItem::transformOriginPoint() const
+{
+ Q_D(const QSGItem);
+ return d->computeTransformOrigin();
+}
+
+qreal QSGItem::z() const
+{
+ Q_D(const QSGItem);
+ return d->z;
+}
+
+void QSGItem::setZ(qreal v)
+{
+ Q_D(QSGItem);
+ if (d->z == v)
+ return;
+
+ d->z = v;
+
+ d->dirty(QSGItemPrivate::ZValue);
+ if (d->parentItem)
+ QSGItemPrivate::get(d->parentItem)->dirty(QSGItemPrivate::ChildrenStackingChanged);
+
+ emit zChanged();
+}
+
+qreal QSGItem::rotation() const
+{
+ Q_D(const QSGItem);
+ return d->rotation;
+}
+
+void QSGItem::setRotation(qreal r)
+{
+ Q_D(QSGItem);
+ if (d->rotation == r)
+ return;
+
+ d->rotation = r;
+
+ d->dirty(QSGItemPrivate::BasicTransform);
+
+ d->itemChange(ItemRotationHasChanged, r);
+
+ emit rotationChanged();
+}
+
+qreal QSGItem::scale() const
+{
+ Q_D(const QSGItem);
+ return d->scale;
+}
+
+void QSGItem::setScale(qreal s)
+{
+ Q_D(QSGItem);
+ if (d->scale == s)
+ return;
+
+ d->scale = s;
+
+ d->dirty(QSGItemPrivate::BasicTransform);
+
+ emit scaleChanged();
+}
+
+qreal QSGItem::opacity() const
+{
+ Q_D(const QSGItem);
+ return d->opacity;
+}
+
+void QSGItem::setOpacity(qreal o)
+{
+ Q_D(QSGItem);
+ if (d->opacity == o)
+ return;
+
+ d->opacity = o;
+
+ d->dirty(QSGItemPrivate::OpacityValue);
+
+ d->itemChange(ItemOpacityHasChanged, o);
+
+ emit opacityChanged();
+}
+
+bool QSGItem::isVisible() const
+{
+ Q_D(const QSGItem);
+ return d->effectiveVisible;
+}
+
+void QSGItem::setVisible(bool v)
+{
+ Q_D(QSGItem);
+ if (v == d->explicitVisible)
+ return;
+
+ d->explicitVisible = v;
+
+ d->setEffectiveVisibleRecur(d->calcEffectiveVisible());
+}
+
+bool QSGItem::isEnabled() const
+{
+ Q_D(const QSGItem);
+ return d->effectiveEnable;
+}
+
+void QSGItem::setEnabled(bool e)
+{
+ Q_D(QSGItem);
+ if (e == d->explicitEnable)
+ return;
+
+ d->explicitEnable = e;
+
+ d->setEffectiveEnableRecur(d->calcEffectiveEnable());
+}
+
+bool QSGItemPrivate::calcEffectiveVisible() const
+{
+ // XXX todo - Should the effective visible of an element with no parent just be the current
+ // effective visible? This would prevent pointless re-processing in the case of an element
+ // moving to/from a no-parent situation, but it is different from what graphics view does.
+ return explicitVisible && (!parentItem || QSGItemPrivate::get(parentItem)->effectiveVisible);
+}
+
+void QSGItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
+{
+ Q_Q(QSGItem);
+
+ if (newEffectiveVisible && !explicitVisible) {
+ // This item locally overrides visibility
+ return;
+ }
+
+ if (newEffectiveVisible == effectiveVisible) {
+ // No change necessary
+ return;
+ }
+
+ effectiveVisible = newEffectiveVisible;
+ dirty(Visible);
+ if (parentItem) QSGItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
+
+ if (canvas) {
+ QSGCanvasPrivate *canvasPriv = QSGCanvasPrivate::get(canvas);
+ if (canvasPriv->mouseGrabberItem == q)
+ q->ungrabMouse();
+ }
+
+ for (int ii = 0; ii < childItems.count(); ++ii)
+ QSGItemPrivate::get(childItems.at(ii))->setEffectiveVisibleRecur(newEffectiveVisible);
+
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Visibility)
+ change.listener->itemVisibilityChanged(q);
+ }
+
+ emit q->visibleChanged();
+}
+
+bool QSGItemPrivate::calcEffectiveEnable() const
+{
+ // XXX todo - Should the effective enable of an element with no parent just be the current
+ // effective enable? This would prevent pointless re-processing in the case of an element
+ // moving to/from a no-parent situation, but it is different from what graphics view does.
+ return explicitEnable && (!parentItem || QSGItemPrivate::get(parentItem)->effectiveEnable);
+}
+
+void QSGItemPrivate::setEffectiveEnableRecur(bool newEffectiveEnable)
+{
+ Q_Q(QSGItem);
+
+ // XXX todo - need to fixup focus
+
+ if (newEffectiveEnable && !explicitEnable) {
+ // This item locally overrides enable
+ return;
+ }
+
+ if (newEffectiveEnable == effectiveEnable) {
+ // No change necessary
+ return;
+ }
+
+ effectiveEnable = newEffectiveEnable;
+
+ if (canvas) {
+ QSGCanvasPrivate *canvasPriv = QSGCanvasPrivate::get(canvas);
+ if (canvasPriv->mouseGrabberItem == q)
+ q->ungrabMouse();
+ }
+
+ for (int ii = 0; ii < childItems.count(); ++ii)
+ QSGItemPrivate::get(childItems.at(ii))->setEffectiveEnableRecur(newEffectiveEnable);
+
+ emit q->enabledChanged();
+}
+
+QString QSGItemPrivate::dirtyToString() const
+{
+#define DIRTY_TO_STRING(value) if (dirtyAttributes & value) { \
+ if (!rv.isEmpty()) \
+ rv.append(QLatin1String("|")); \
+ rv.append(QLatin1String(#value)); \
+}
+
+// QString rv = QLatin1String("0x") + QString::number(dirtyAttributes, 16);
+ QString rv;
+
+ DIRTY_TO_STRING(TransformOrigin);
+ DIRTY_TO_STRING(Transform);
+ DIRTY_TO_STRING(BasicTransform);
+ DIRTY_TO_STRING(Position);
+ DIRTY_TO_STRING(Size);
+ DIRTY_TO_STRING(ZValue);
+ DIRTY_TO_STRING(Content);
+ DIRTY_TO_STRING(Smooth);
+ DIRTY_TO_STRING(OpacityValue);
+ DIRTY_TO_STRING(ChildrenChanged);
+ DIRTY_TO_STRING(ChildrenStackingChanged);
+ DIRTY_TO_STRING(ParentChanged);
+ DIRTY_TO_STRING(Clip);
+ DIRTY_TO_STRING(Canvas);
+ DIRTY_TO_STRING(EffectReference);
+ DIRTY_TO_STRING(Visible);
+ DIRTY_TO_STRING(HideReference);
+
+ return rv;
+}
+
+void QSGItemPrivate::dirty(DirtyType type)
+{
+ Q_Q(QSGItem);
+ if (type & (TransformOrigin | Transform | BasicTransform | Position | Size))
+ transformChanged();
+
+ if (!(dirtyAttributes & type) || (canvas && !prevDirtyItem)) {
+ dirtyAttributes |= type;
+ if (canvas) {
+ addToDirtyList();
+ QSGCanvasPrivate::get(canvas)->dirtyItem(q);
+ }
+ }
+}
+
+void QSGItemPrivate::addToDirtyList()
+{
+ Q_Q(QSGItem);
+
+ Q_ASSERT(canvas);
+ if (!prevDirtyItem) {
+ Q_ASSERT(!nextDirtyItem);
+
+ QSGCanvasPrivate *p = QSGCanvasPrivate::get(canvas);
+ nextDirtyItem = p->dirtyItemList;
+ if (nextDirtyItem) QSGItemPrivate::get(nextDirtyItem)->prevDirtyItem = &nextDirtyItem;
+ prevDirtyItem = &p->dirtyItemList;
+ p->dirtyItemList = q;
+ p->dirtyItem(q);
+ }
+ Q_ASSERT(prevDirtyItem);
+}
+
+void QSGItemPrivate::removeFromDirtyList()
+{
+ if (prevDirtyItem) {
+ if (nextDirtyItem) QSGItemPrivate::get(nextDirtyItem)->prevDirtyItem = prevDirtyItem;
+ *prevDirtyItem = nextDirtyItem;
+ prevDirtyItem = 0;
+ nextDirtyItem = 0;
+ }
+ Q_ASSERT(!prevDirtyItem);
+ Q_ASSERT(!nextDirtyItem);
+}
+
+void QSGItemPrivate::refFromEffectItem(bool hide)
+{
+ ++effectRefCount;
+ if (1 == effectRefCount) {
+ dirty(EffectReference);
+ if (parentItem) QSGItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
+ }
+ if (hide) {
+ if (++hideRefCount == 1)
+ dirty(HideReference);
+ }
+}
+
+void QSGItemPrivate::derefFromEffectItem(bool unhide)
+{
+ Q_ASSERT(effectRefCount);
+ --effectRefCount;
+ if (0 == effectRefCount) {
+ dirty(EffectReference);
+ if (parentItem) QSGItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged);
+ }
+ if (unhide) {
+ if (--hideRefCount == 0)
+ dirty(HideReference);
+ }
+}
+
+void QSGItemPrivate::itemChange(QSGItem::ItemChange change, const QSGItem::ItemChangeData &data)
+{
+ Q_Q(QSGItem);
+ switch(change) {
+ case QSGItem::ItemChildAddedChange:
+ q->itemChange(change, data);
+ if (_contents && componentComplete)
+ _contents->childAdded(data.item);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Children) {
+ change.listener->itemChildAdded(q, data.item);
+ }
+ }
+ break;
+ case QSGItem::ItemChildRemovedChange:
+ q->itemChange(change, data);
+ if (_contents && componentComplete)
+ _contents->childRemoved(data.item);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Children) {
+ change.listener->itemChildRemoved(q, data.item);
+ }
+ }
+ break;
+ case QSGItem::ItemSceneChange:
+ q->itemChange(change, data);
+ break;
+ case QSGItem::ItemVisibleHasChanged:
+ q->itemChange(change, data);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Visibility) {
+ change.listener->itemVisibilityChanged(q);
+ }
+ }
+ break;
+ case QSGItem::ItemParentHasChanged:
+ q->itemChange(change, data);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Parent) {
+ change.listener->itemParentChanged(q, data.item);
+ }
+ }
+ break;
+ case QSGItem::ItemOpacityHasChanged:
+ q->itemChange(change, data);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Opacity) {
+ change.listener->itemOpacityChanged(q);
+ }
+ }
+ break;
+ case QSGItem::ItemActiveFocusHasChanged:
+ q->itemChange(change, data);
+ break;
+ case QSGItem::ItemRotationHasChanged:
+ q->itemChange(change, data);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QSGItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QSGItemPrivate::Rotation) {
+ change.listener->itemRotationChanged(q);
+ }
+ }
+ break;
+ }
+}
+
+bool QSGItem::smooth() const
+{
+ Q_D(const QSGItem);
+ return d->smooth;
+}
+
+void QSGItem::setSmooth(bool smooth)
+{
+ Q_D(QSGItem);
+ if (d->smooth == smooth)
+ return;
+
+ d->smooth = smooth;
+ d->dirty(QSGItemPrivate::Smooth);
+
+ emit smoothChanged(smooth);
+}
+
+QSGItem::Flags QSGItem::flags() const
+{
+ Q_D(const QSGItem);
+ return (QSGItem::Flags)d->flags;
+}
+
+void QSGItem::setFlag(Flag flag, bool enabled)
+{
+ Q_D(QSGItem);
+ if (enabled)
+ setFlags((Flags)(d->flags | (quint32)flag));
+ else
+ setFlags((Flags)(d->flags & ~(quint32)flag));
+}
+
+void QSGItem::setFlags(Flags flags)
+{
+ Q_D(QSGItem);
+
+ if ((flags & ItemIsFocusScope) != (d->flags & ItemIsFocusScope)) {
+ if (flags & ItemIsFocusScope && !d->childItems.isEmpty() && d->canvas) {
+ qWarning("QSGItem: Cannot set FocusScope once item has children and is in a canvas.");
+ flags &= ~ItemIsFocusScope;
+ } else if (d->flags & ItemIsFocusScope) {
+ qWarning("QSGItem: Cannot unset FocusScope flag.");
+ flags |= ItemIsFocusScope;
+ }
+ }
+
+ if ((flags & ItemClipsChildrenToShape ) != (d->flags & ItemClipsChildrenToShape))
+ d->dirty(QSGItemPrivate::Clip);
+
+ d->flags = flags;
+}
+
+qreal QSGItem::x() const
+{
+ Q_D(const QSGItem);
+ return d->x;
+}
+
+qreal QSGItem::y() const
+{
+ Q_D(const QSGItem);
+ return d->y;
+}
+
+QPointF QSGItem::pos() const
+{
+ Q_D(const QSGItem);
+ return QPointF(d->x, d->y);
+}
+
+void QSGItem::setX(qreal v)
+{
+ Q_D(QSGItem);
+ if (d->x == v)
+ return;
+
+ qreal oldx = d->x;
+ d->x = v;
+
+ d->dirty(QSGItemPrivate::Position);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(oldx, y(), width(), height()));
+}
+
+void QSGItem::setY(qreal v)
+{
+ Q_D(QSGItem);
+ if (d->y == v)
+ return;
+
+ qreal oldy = d->y;
+ d->y = v;
+
+ d->dirty(QSGItemPrivate::Position);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), oldy, width(), height()));
+}
+
+void QSGItem::setPos(const QPointF &pos)
+{
+ Q_D(QSGItem);
+ if (QPointF(d->x, d->y) == pos)
+ return;
+
+ qreal oldx = d->x;
+ qreal oldy = d->y;
+
+ d->x = pos.x();
+ d->y = pos.y();
+
+ d->dirty(QSGItemPrivate::Position);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(oldx, oldy, width(), height()));
+}
+
+qreal QSGItem::width() const
+{
+ Q_D(const QSGItem);
+ return d->width;
+}
+
+void QSGItem::setWidth(qreal w)
+{
+ Q_D(QSGItem);
+ if (qIsNaN(w))
+ return;
+
+ d->widthValid = true;
+ if (d->width == w)
+ return;
+
+ qreal oldWidth = d->width;
+ d->width = w;
+
+ d->dirty(QSGItemPrivate::Size);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), oldWidth, height()));
+}
+
+void QSGItem::resetWidth()
+{
+ Q_D(QSGItem);
+ d->widthValid = false;
+ setImplicitWidth(implicitWidth());
+}
+
+void QSGItemPrivate::implicitWidthChanged()
+{
+ Q_Q(QSGItem);
+ emit q->implicitWidthChanged();
+}
+
+qreal QSGItemPrivate::getImplicitWidth() const
+{
+ return implicitWidth;
+}
+
+qreal QSGItem::implicitWidth() const
+{
+ Q_D(const QSGItem);
+ return d->getImplicitWidth();
+}
+
+void QSGItem::setImplicitWidth(qreal w)
+{
+ Q_D(QSGItem);
+ bool changed = w != d->implicitWidth;
+ d->implicitWidth = w;
+ if (d->width == w || widthValid()) {
+ if (changed)
+ d->implicitWidthChanged();
+ return;
+ }
+
+ qreal oldWidth = d->width;
+ d->width = w;
+
+ d->dirty(QSGItemPrivate::Size);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), oldWidth, height()));
+
+ if (changed)
+ d->implicitWidthChanged();
+}
+
+bool QSGItem::widthValid() const
+{
+ Q_D(const QSGItem);
+ return d->widthValid;
+}
+
+qreal QSGItem::height() const
+{
+ Q_D(const QSGItem);
+ return d->height;
+}
+
+void QSGItem::setHeight(qreal h)
+{
+ Q_D(QSGItem);
+ if (qIsNaN(h))
+ return;
+
+ d->heightValid = true;
+ if (d->height == h)
+ return;
+
+ qreal oldHeight = d->height;
+ d->height = h;
+
+ d->dirty(QSGItemPrivate::Size);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), width(), oldHeight));
+}
+
+void QSGItem::resetHeight()
+{
+ Q_D(QSGItem);
+ d->heightValid = false;
+ setImplicitHeight(implicitHeight());
+}
+
+void QSGItemPrivate::implicitHeightChanged()
+{
+ Q_Q(QSGItem);
+ emit q->implicitHeightChanged();
+}
+
+qreal QSGItemPrivate::getImplicitHeight() const
+{
+ return implicitHeight;
+}
+
+qreal QSGItem::implicitHeight() const
+{
+ Q_D(const QSGItem);
+ return d->getImplicitHeight();
+}
+
+void QSGItem::setImplicitHeight(qreal h)
+{
+ Q_D(QSGItem);
+ bool changed = h != d->implicitHeight;
+ d->implicitHeight = h;
+ if (d->height == h || heightValid()) {
+ if (changed)
+ d->implicitHeightChanged();
+ return;
+ }
+
+ qreal oldHeight = d->height;
+ d->height = h;
+
+ d->dirty(QSGItemPrivate::Size);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), width(), oldHeight));
+
+ if (changed)
+ d->implicitHeightChanged();
+}
+
+bool QSGItem::heightValid() const
+{
+ Q_D(const QSGItem);
+ return d->heightValid;
+}
+
+void QSGItem::setSize(const QSizeF &size)
+{
+ Q_D(QSGItem);
+ d->heightValid = true;
+ d->widthValid = true;
+
+ if (QSizeF(d->width, d->height) == size)
+ return;
+
+ qreal oldHeight = d->height;
+ qreal oldWidth = d->width;
+ d->height = size.height();
+ d->width = size.width();
+
+ d->dirty(QSGItemPrivate::Size);
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), oldWidth, oldHeight));
+}
+
+bool QSGItem::hasActiveFocus() const
+{
+ Q_D(const QSGItem);
+ return d->activeFocus;
+}
+
+bool QSGItem::hasFocus() const
+{
+ Q_D(const QSGItem);
+ return d->focus;
+}
+
+void QSGItem::setFocus(bool focus)
+{
+ Q_D(QSGItem);
+ if (d->focus == focus)
+ return;
+
+ if (d->canvas) {
+ // Need to find our nearest focus scope
+ QSGItem *scope = parentItem();
+ while (scope && !scope->isFocusScope())
+ scope = scope->parentItem();
+ if (focus)
+ QSGCanvasPrivate::get(d->canvas)->setFocusInScope(scope, this);
+ else
+ QSGCanvasPrivate::get(d->canvas)->clearFocusInScope(scope, this);
+ } else {
+ d->focus = focus;
+ emit focusChanged(focus);
+ }
+}
+
+bool QSGItem::isFocusScope() const
+{
+ return flags() & ItemIsFocusScope;
+}
+
+QSGItem *QSGItem::scopedFocusItem() const
+{
+ Q_D(const QSGItem);
+ if (!isFocusScope())
+ return 0;
+ else
+ return d->subFocusItem;
+}
+
+
+Qt::MouseButtons QSGItem::acceptedMouseButtons() const
+{
+ Q_D(const QSGItem);
+ return d->acceptedMouseButtons;
+}
+
+void QSGItem::setAcceptedMouseButtons(Qt::MouseButtons buttons)
+{
+ Q_D(QSGItem);
+ d->acceptedMouseButtons = buttons;
+}
+
+bool QSGItem::filtersChildMouseEvents() const
+{
+ Q_D(const QSGItem);
+ return d->filtersChildMouseEvents;
+}
+
+void QSGItem::setFiltersChildMouseEvents(bool filter)
+{
+ Q_D(QSGItem);
+ d->filtersChildMouseEvents = filter;
+}
+
+bool QSGItem::isUnderMouse() const
+{
+ Q_D(const QSGItem);
+ if (!d->canvas)
+ return false;
+
+ QPoint cursorPos = QCursor::pos();
+ if (QRectF(0, 0, width(), height()).contains(mapFromScene(d->canvas->mapFromGlobal(cursorPos))))
+ return true;
+ return false;
+}
+
+bool QSGItem::acceptHoverEvents() const
+{
+ Q_D(const QSGItem);
+ return d->hoverEnabled;
+}
+
+void QSGItem::setAcceptHoverEvents(bool enabled)
+{
+ Q_D(QSGItem);
+ d->hoverEnabled = enabled;
+
+ if (d->canvas && d->hoverEnabled && !d->canvas->hasMouseTracking())
+ d->canvas->setMouseTracking(true);
+}
+
+void QSGItem::grabMouse()
+{
+ Q_D(QSGItem);
+ if (!d->canvas)
+ return;
+ QSGCanvasPrivate *canvasPriv = QSGCanvasPrivate::get(d->canvas);
+ if (canvasPriv->mouseGrabberItem == this)
+ return;
+
+ QSGItem *oldGrabber = canvasPriv->mouseGrabberItem;
+ canvasPriv->mouseGrabberItem = this;
+ if (oldGrabber)
+ oldGrabber->mouseUngrabEvent();
+}
+
+void QSGItem::ungrabMouse()
+{
+ Q_D(QSGItem);
+ if (!d->canvas)
+ return;
+ QSGCanvasPrivate *canvasPriv = QSGCanvasPrivate::get(d->canvas);
+ if (canvasPriv->mouseGrabberItem != this) {
+ qWarning("QSGItem::ungrabMouse(): Item is not the mouse grabber.");
+ return;
+ }
+
+ canvasPriv->mouseGrabberItem = 0;
+ mouseUngrabEvent();
+}
+
+bool QSGItem::keepMouseGrab() const
+{
+ Q_D(const QSGItem);
+ return d->keepMouse;
+}
+
+void QSGItem::setKeepMouseGrab(bool keep)
+{
+ Q_D(QSGItem);
+ d->keepMouse = keep;
+}
+
+QPointF QSGItem::mapToItem(const QSGItem *item, const QPointF &point) const
+{
+ QPointF p = mapToScene(point);
+ if (item)
+ p = item->mapFromScene(p);
+ return p;
+}
+
+QPointF QSGItem::mapToScene(const QPointF &point) const
+{
+ Q_D(const QSGItem);
+ return d->itemToCanvasTransform().map(point);
+}
+
+QRectF QSGItem::mapRectToItem(const QSGItem *item, const QRectF &rect) const
+{
+ Q_D(const QSGItem);
+ QTransform t = d->itemToCanvasTransform();
+ if (item)
+ t *= QSGItemPrivate::get(item)->canvasToItemTransform();
+ return t.mapRect(rect);
+}
+
+QRectF QSGItem::mapRectToScene(const QRectF &rect) const
+{
+ Q_D(const QSGItem);
+ return d->itemToCanvasTransform().mapRect(rect);
+}
+
+QPointF QSGItem::mapFromItem(const QSGItem *item, const QPointF &point) const
+{
+ QPointF p = item?item->mapToScene(point):point;
+ return mapFromScene(p);
+}
+
+QPointF QSGItem::mapFromScene(const QPointF &point) const
+{
+ Q_D(const QSGItem);
+ return d->canvasToItemTransform().map(point);
+}
+
+QRectF QSGItem::mapRectFromItem(const QSGItem *item, const QRectF &rect) const
+{
+ Q_D(const QSGItem);
+ QTransform t = item?QSGItemPrivate::get(item)->itemToCanvasTransform():QTransform();
+ t *= d->canvasToItemTransform();
+ return t.mapRect(rect);
+}
+
+QRectF QSGItem::mapRectFromScene(const QRectF &rect) const
+{
+ Q_D(const QSGItem);
+ return d->canvasToItemTransform().mapRect(rect);
+}
+
+bool QSGItem::event(QEvent *ev)
+{
+ return QObject::event(ev);
+
+#if 0
+ if (ev->type() == QEvent::PolishRequest) {
+ Q_D(QSGItem);
+ d->polishScheduled = false;
+ updatePolish();
+ return true;
+ } else {
+ return QObject::event(ev);
+ }
+#endif
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, QSGItem *item)
+{
+ if (!item) {
+ debug << "QSGItem(0)";
+ return debug;
+ }
+
+ debug << item->metaObject()->className() << "(this =" << ((void*)item)
+ << ", name=" << item->objectName()
+ << ", parent =" << ((void*)item->parentItem())
+ << ", geometry =" << QRectF(item->pos(), QSizeF(item->width(), item->height()))
+ << ", z =" << item->z() << ')';
+ return debug;
+}
+#endif
+
+qint64 QSGItemPrivate::consistentTime = -1;
+void QSGItemPrivate::setConsistentTime(qint64 t)
+{
+ consistentTime = t;
+}
+
+class QElapsedTimerConsistentTimeHack
+{
+public:
+ void start() {
+ t1 = QSGItemPrivate::consistentTime;
+ t2 = 0;
+ }
+ qint64 elapsed() {
+ return QSGItemPrivate::consistentTime - t1;
+ }
+ qint64 restart() {
+ qint64 val = QSGItemPrivate::consistentTime - t1;
+ t1 = QSGItemPrivate::consistentTime;
+ t2 = 0;
+ return val;
+ }
+
+private:
+ qint64 t1;
+ qint64 t2;
+};
+
+void QSGItemPrivate::start(QElapsedTimer &t)
+{
+ if (QSGItemPrivate::consistentTime == -1)
+ t.start();
+ else
+ ((QElapsedTimerConsistentTimeHack*)&t)->start();
+}
+
+qint64 QSGItemPrivate::elapsed(QElapsedTimer &t)
+{
+ if (QSGItemPrivate::consistentTime == -1)
+ return t.elapsed();
+ else
+ return ((QElapsedTimerConsistentTimeHack*)&t)->elapsed();
+}
+
+qint64 QSGItemPrivate::restart(QElapsedTimer &t)
+{
+ if (QSGItemPrivate::consistentTime == -1)
+ return t.restart();
+ else
+ return ((QElapsedTimerConsistentTimeHack*)&t)->restart();
+}
+
+QT_END_NAMESPACE
+
+#include <moc_qsgitem.cpp>
diff --git a/src/declarative/items/qsgitem.h b/src/declarative/items/qsgitem.h
new file mode 100644
index 0000000000..564d819000
--- /dev/null
+++ b/src/declarative/items/qsgitem.h
@@ -0,0 +1,399 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGITEM_H
+#define QSGITEM_H
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qaction.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class QSGTransformPrivate;
+class QSGTransform : public QObject
+{
+ Q_OBJECT
+public:
+ QSGTransform(QObject *parent = 0);
+ ~QSGTransform();
+
+ void appendToItem(QSGItem *);
+ void prependToItem(QSGItem *);
+
+ virtual void applyTo(QMatrix4x4 *matrix) const = 0;
+
+protected Q_SLOTS:
+ void update();
+
+protected:
+ QSGTransform(QSGTransformPrivate &dd, QObject *parent);
+
+private:
+ Q_DECLARE_PRIVATE(QSGTransform);
+};
+
+class QDeclarativeState;
+class QSGAnchorLine;
+class QDeclarativeTransition;
+class QSGKeyEvent;
+class QSGAnchors;
+class QSGItemPrivate;
+class QSGCanvas;
+class QSGEngine;
+class QTouchEvent;
+class QSGNode;
+class QSGTransformNode;
+class Q_DECLARATIVE_EXPORT QSGItem : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+
+ Q_PROPERTY(QSGItem *parent READ parentItem WRITE setParentItem NOTIFY parentChanged DESIGNABLE false FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QDeclarativeListProperty<QObject> data READ data DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QDeclarativeListProperty<QObject> resources READ resources DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QDeclarativeListProperty<QSGItem> children READ children NOTIFY childrenChanged DESIGNABLE false)
+
+ Q_PROPERTY(QPointF pos READ pos FINAL)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged FINAL)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged FINAL)
+ Q_PROPERTY(qreal z READ z WRITE setZ NOTIFY zChanged FINAL)
+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged RESET resetWidth FINAL)
+ Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged RESET resetHeight FINAL)
+
+ Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged FINAL)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QDeclarativeListProperty<QDeclarativeState> states READ states DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QDeclarativeListProperty<QDeclarativeTransition> transitions READ transitions DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QString state READ state WRITE setState NOTIFY stateChanged)
+ Q_PROPERTY(QRectF childrenRect READ childrenRect NOTIFY childrenRectChanged DESIGNABLE false FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchors * anchors READ anchors DESIGNABLE false CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine left READ left CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine right READ right CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine horizontalCenter READ horizontalCenter CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine top READ top CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine bottom READ bottom CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine verticalCenter READ verticalCenter CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QSGItem::d_func(), QSGAnchorLine baseline READ baseline CONSTANT FINAL)
+ Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged)
+
+ Q_PROPERTY(bool clip READ clip WRITE setClip NOTIFY clipChanged)
+
+ Q_PROPERTY(bool focus READ hasFocus WRITE setFocus NOTIFY focusChanged FINAL)
+ Q_PROPERTY(bool activeFocus READ hasActiveFocus NOTIFY activeFocusChanged FINAL)
+
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged)
+ Q_PROPERTY(TransformOrigin transformOrigin READ transformOrigin WRITE setTransformOrigin NOTIFY transformOriginChanged)
+ Q_PROPERTY(QPointF transformOriginPoint READ transformOriginPoint) // XXX todo - notify?
+ Q_PROPERTY(QDeclarativeListProperty<QSGTransform> transform READ transform DESIGNABLE false FINAL)
+
+ Q_PROPERTY(bool smooth READ smooth WRITE setSmooth NOTIFY smoothChanged)
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged)
+
+ Q_ENUMS(TransformOrigin)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ enum Flag {
+ ItemClipsChildrenToShape = 0x01,
+ ItemAcceptsInputMethod = 0x02,
+ ItemIsFocusScope = 0x04,
+ ItemHasContents = 0x08,
+ // Remember to increment the size of QSGItemPrivate::flags
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ enum ItemChange {
+ ItemChildAddedChange, // value.item
+ ItemChildRemovedChange, // value.item
+ ItemSceneChange, // value.canvas
+ ItemVisibleHasChanged, // value.realValue
+ ItemParentHasChanged, // value.item
+ ItemOpacityHasChanged, // value.realValue
+ ItemActiveFocusHasChanged, // value.boolValue
+ ItemRotationHasChanged, // value.realValue
+ };
+
+ union ItemChangeData {
+ ItemChangeData(QSGItem *v) : item(v) {}
+ ItemChangeData(QSGCanvas *v) : canvas(v) {}
+ ItemChangeData(qreal v) : realValue(v) {}
+ ItemChangeData(bool v) : boolValue(v) {}
+
+ QSGItem *item;
+ QSGCanvas *canvas;
+ qreal realValue;
+ bool boolValue;
+ };
+
+ enum TransformOrigin {
+ TopLeft, Top, TopRight,
+ Left, Center, Right,
+ BottomLeft, Bottom, BottomRight
+ };
+
+ QSGItem(QSGItem *parent = 0);
+ virtual ~QSGItem();
+
+ QSGEngine *sceneGraphEngine() const;
+
+ QSGCanvas *canvas() const;
+ QSGItem *parentItem() const;
+ void setParentItem(QSGItem *parent);
+ void stackBefore(const QSGItem *);
+ void stackAfter(const QSGItem *);
+
+ QRectF childrenRect();
+ QList<QSGItem *> childItems() const;
+
+ bool clip() const;
+ void setClip(bool);
+
+ qreal baselineOffset() const;
+ void setBaselineOffset(qreal);
+
+ QDeclarativeListProperty<QSGTransform> transform();
+
+ qreal x() const;
+ qreal y() const;
+ QPointF pos() const;
+ void setX(qreal);
+ void setY(qreal);
+ void setPos(const QPointF &);
+
+ qreal width() const;
+ void setWidth(qreal);
+ void resetWidth();
+ qreal implicitWidth() const;
+
+ qreal height() const;
+ void setHeight(qreal);
+ void resetHeight();
+ qreal implicitHeight() const;
+
+ void setSize(const QSizeF &size);
+
+ TransformOrigin transformOrigin() const;
+ void setTransformOrigin(TransformOrigin);
+ QPointF transformOriginPoint() const;
+
+ qreal z() const;
+ void setZ(qreal);
+
+ qreal rotation() const;
+ void setRotation(qreal);
+ qreal scale() const;
+ void setScale(qreal);
+
+ qreal opacity() const;
+ void setOpacity(qreal);
+
+ bool isVisible() const;
+ void setVisible(bool);
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ bool smooth() const;
+ void setSmooth(bool);
+
+ Flags flags() const;
+ void setFlag(Flag flag, bool enabled = true);
+ void setFlags(Flags flags);
+
+ QRectF boundingRect() const;
+
+ bool hasActiveFocus() const;
+ bool hasFocus() const;
+ void setFocus(bool);
+ bool isFocusScope() const;
+ QSGItem *scopedFocusItem() const;
+
+ Qt::MouseButtons acceptedMouseButtons() const;
+ void setAcceptedMouseButtons(Qt::MouseButtons buttons);
+ bool acceptHoverEvents() const;
+ void setAcceptHoverEvents(bool enabled);
+
+ bool isUnderMouse() const;
+ void grabMouse();
+ void ungrabMouse();
+ bool keepMouseGrab() const;
+ void setKeepMouseGrab(bool);
+ bool filtersChildMouseEvents() const;
+ void setFiltersChildMouseEvents(bool filter);
+
+ QTransform itemTransform(QSGItem *, bool *) const;
+ QPointF mapToItem(const QSGItem *item, const QPointF &point) const;
+ QPointF mapToScene(const QPointF &point) const;
+ QRectF mapRectToItem(const QSGItem *item, const QRectF &rect) const;
+ QRectF mapRectToScene(const QRectF &rect) const;
+ QPointF mapFromItem(const QSGItem *item, const QPointF &point) const;
+ QPointF mapFromScene(const QPointF &point) const;
+ QRectF mapRectFromItem(const QSGItem *item, const QRectF &rect) const;
+ QRectF mapRectFromScene(const QRectF &rect) const;
+
+ void polish();
+
+ Q_INVOKABLE QScriptValue mapFromItem(const QScriptValue &item, qreal x, qreal y) const;
+ Q_INVOKABLE QScriptValue mapToItem(const QScriptValue &item, qreal x, qreal y) const;
+ Q_INVOKABLE void forceActiveFocus();
+ Q_INVOKABLE QSGItem *childAt(qreal x, qreal y) const;
+
+ Qt::InputMethodHints inputMethodHints() const;
+ void setInputMethodHints(Qt::InputMethodHints hints);
+ virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+ struct UpdatePaintNodeData {
+ QSGTransformNode *transformNode;
+ private:
+ friend class QSGCanvasPrivate;
+ UpdatePaintNodeData();
+ };
+
+public Q_SLOTS:
+ void update();
+ void updateMicroFocus();
+
+Q_SIGNALS:
+ void childrenRectChanged(const QRectF &);
+ void baselineOffsetChanged(qreal);
+ void stateChanged(const QString &);
+ void focusChanged(bool);
+ void activeFocusChanged(bool);
+ void parentChanged(QSGItem *);
+ void transformOriginChanged(TransformOrigin);
+ void smoothChanged(bool);
+ void clipChanged(bool);
+
+ // XXX todo
+ void childrenChanged();
+ void opacityChanged();
+ void enabledChanged();
+ void visibleChanged();
+ void rotationChanged();
+ void scaleChanged();
+
+ void xChanged();
+ void yChanged();
+ void widthChanged();
+ void heightChanged();
+ void zChanged();
+ void implicitWidthChanged();
+ void implicitHeightChanged();
+
+protected:
+ virtual bool event(QEvent *);
+
+ bool isComponentComplete() const;
+ virtual void itemChange(ItemChange, const ItemChangeData &);
+
+ void setImplicitWidth(qreal);
+ bool widthValid() const; // ### better name?
+ void setImplicitHeight(qreal);
+ bool heightValid() const; // ### better name?
+
+ virtual void classBegin();
+ virtual void componentComplete();
+
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void keyReleaseEvent(QKeyEvent *event);
+ virtual void inputMethodEvent(QInputMethodEvent *);
+ virtual void focusInEvent(QFocusEvent *);
+ virtual void focusOutEvent(QFocusEvent *);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseUngrabEvent(); // XXX todo - params?
+ virtual void wheelEvent(QGraphicsSceneWheelEvent *event);
+ virtual void touchEvent(QTouchEvent *event);
+ virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ virtual bool childMouseEventFilter(QSGItem *, QEvent *);
+
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual void updatePolish();
+
+protected:
+ QSGItem(QSGItemPrivate &dd, QSGItem *parent = 0);
+
+private:
+ friend class QSGCanvas;
+ friend class QSGCanvasPrivate;
+ friend class QSGRenderer;
+ Q_DISABLE_COPY(QSGItem)
+ Q_DECLARE_PRIVATE(QSGItem)
+};
+
+// XXX todo
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGItem::Flags)
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug Q_DECLARATIVE_EXPORT operator<<(QDebug debug, QSGItem *item);
+#endif
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGItem)
+QML_DECLARE_TYPE(QSGTransform)
+
+QT_END_HEADER
+
+#endif // QSGITEM_H
diff --git a/src/declarative/items/qsgitem_p.h b/src/declarative/items/qsgitem_p.h
new file mode 100644
index 0000000000..a13fd6a85a
--- /dev/null
+++ b/src/declarative/items/qsgitem_p.h
@@ -0,0 +1,710 @@
+// Commit: 5c783d0a9a912816813945387903857a314040b5
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGITEM_P_H
+#define QSGITEM_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 "qsgitem.h"
+
+#include "qsganchors_p.h"
+#include "qsganchors_p_p.h"
+#include "qsgitemchangelistener_p.h"
+
+#include "qsgcanvas_p.h"
+
+#include "qsgnode.h"
+#include "qsgclipnode_p.h"
+
+#include <private/qpodvector_p.h>
+#include <private/qdeclarativestate_p.h>
+#include <private/qdeclarativenullablevalue_p_p.h>
+#include <private/qdeclarativenotifier_p.h>
+#include <private/qdeclarativeglobal_p.h>
+
+#include <qdeclarative.h>
+#include <qdeclarativecontext.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qelapsedtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QSGItemKeyFilter;
+class QSGLayoutMirroringAttached;
+
+//### merge into private?
+class QSGContents : public QObject, public QSGItemChangeListener
+{
+ Q_OBJECT
+public:
+ QSGContents(QSGItem *item);
+ ~QSGContents();
+
+ QRectF rectF() const;
+
+ void childRemoved(QSGItem *item);
+ void childAdded(QSGItem *item);
+
+ void calcGeometry() { calcWidth(); calcHeight(); }
+ void complete();
+
+Q_SIGNALS:
+ void rectChanged(QRectF);
+
+protected:
+ void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
+ void itemDestroyed(QSGItem *item);
+ //void itemVisibilityChanged(QSGItem *item)
+
+private:
+ void calcHeight(QSGItem *changed = 0);
+ void calcWidth(QSGItem *changed = 0);
+
+ QSGItem *m_item;
+ qreal m_x;
+ qreal m_y;
+ qreal m_width;
+ qreal m_height;
+};
+
+class QSGTransformPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGTransform);
+public:
+ static QSGTransformPrivate* get(QSGTransform *transform) { return transform->d_func(); }
+
+ QSGTransformPrivate();
+
+ QList<QSGItem *> items;
+};
+
+class Q_DECLARATIVE_EXPORT QSGItemPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGItem)
+
+public:
+ static QSGItemPrivate* get(QSGItem *item) { return item->d_func(); }
+ static const QSGItemPrivate* get(const QSGItem *item) { return item->d_func(); }
+
+ QSGItemPrivate();
+ void init(QSGItem *parent);
+
+ QDeclarativeListProperty<QObject> data();
+ QDeclarativeListProperty<QObject> resources();
+ QDeclarativeListProperty<QSGItem> children();
+
+ QDeclarativeListProperty<QDeclarativeState> states();
+ QDeclarativeListProperty<QDeclarativeTransition> transitions();
+
+ QString state() const;
+ void setState(const QString &);
+
+ QSGAnchorLine left() const;
+ QSGAnchorLine right() const;
+ QSGAnchorLine horizontalCenter() const;
+ QSGAnchorLine top() const;
+ QSGAnchorLine bottom() const;
+ QSGAnchorLine verticalCenter() const;
+ QSGAnchorLine baseline() const;
+
+ // data property
+ static void data_append(QDeclarativeListProperty<QObject> *, QObject *);
+ static int data_count(QDeclarativeListProperty<QObject> *);
+ static QObject *data_at(QDeclarativeListProperty<QObject> *, int);
+ static void data_clear(QDeclarativeListProperty<QObject> *);
+
+ // resources property
+ static QObject *resources_at(QDeclarativeListProperty<QObject> *, int);
+ static void resources_append(QDeclarativeListProperty<QObject> *, QObject *);
+ static int resources_count(QDeclarativeListProperty<QObject> *);
+ static void resources_clear(QDeclarativeListProperty<QObject> *);
+
+ // children property
+ static void children_append(QDeclarativeListProperty<QSGItem> *, QSGItem *);
+ static int children_count(QDeclarativeListProperty<QSGItem> *);
+ static QSGItem *children_at(QDeclarativeListProperty<QSGItem> *, int);
+ static void children_clear(QDeclarativeListProperty<QSGItem> *);
+
+ // transform property
+ static int transform_count(QDeclarativeListProperty<QSGTransform> *list);
+ static void transform_append(QDeclarativeListProperty<QSGTransform> *list, QSGTransform *);
+ static QSGTransform *transform_at(QDeclarativeListProperty<QSGTransform> *list, int);
+ static void transform_clear(QDeclarativeListProperty<QSGTransform> *list);
+
+ QSGAnchors *anchors() const;
+ mutable QSGAnchors *_anchors;
+ QSGContents *_contents;
+
+ QDeclarativeNullableValue<qreal> baselineOffset;
+
+ struct AnchorLines {
+ AnchorLines(QSGItem *);
+ QSGAnchorLine left;
+ QSGAnchorLine right;
+ QSGAnchorLine hCenter;
+ QSGAnchorLine top;
+ QSGAnchorLine bottom;
+ QSGAnchorLine vCenter;
+ QSGAnchorLine baseline;
+ };
+ mutable AnchorLines *_anchorLines;
+ AnchorLines *anchorLines() const;
+
+ enum ChangeType {
+ Geometry = 0x01,
+ SiblingOrder = 0x02,
+ Visibility = 0x04,
+ Opacity = 0x08,
+ Destroyed = 0x10,
+ Parent = 0x20,
+ Children = 0x40,
+ Rotation = 0x80,
+ };
+
+ Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
+
+ struct ChangeListener {
+ ChangeListener(QSGItemChangeListener *l, QSGItemPrivate::ChangeTypes t) : listener(l), types(t) {}
+ QSGItemChangeListener *listener;
+ QSGItemPrivate::ChangeTypes types;
+ bool operator==(const ChangeListener &other) const { return listener == other.listener && types == other.types; }
+ };
+
+ void addItemChangeListener(QSGItemChangeListener *listener, ChangeTypes types) {
+ changeListeners.append(ChangeListener(listener, types));
+ }
+ void removeItemChangeListener(QSGItemChangeListener *, ChangeTypes types);
+ QPODVector<ChangeListener,4> changeListeners;
+
+ QDeclarativeStateGroup *_states();
+ QDeclarativeStateGroup *_stateGroup;
+
+ QSGItem::TransformOrigin origin:5;
+ quint32 flags:4;
+ bool widthValid:1;
+ bool heightValid:1;
+ bool componentComplete:1;
+ bool keepMouse:1;
+ bool hoverEnabled:1;
+ bool smooth:1;
+ bool focus:1;
+ bool activeFocus:1;
+ bool notifiedFocus:1;
+ bool notifiedActiveFocus:1;
+ bool filtersChildMouseEvents:1;
+ bool explicitVisible:1;
+ bool effectiveVisible:1;
+ bool explicitEnable:1;
+ bool effectiveEnable:1;
+ bool polishScheduled:1;
+ bool inheritedLayoutMirror:1;
+ bool effectiveLayoutMirror:1;
+ bool isMirrorImplicit:1;
+ bool inheritMirrorFromParent:1;
+ bool inheritMirrorFromItem:1;
+ quint32 dummy:2;
+
+ QSGCanvas *canvas;
+ QSGContext *sceneGraphContext() const { return static_cast<QSGCanvasPrivate *>(QObjectPrivate::get(canvas))->context; }
+
+ QSGItem *parentItem;
+ QList<QSGItem *> childItems;
+ QList<QSGItem *> paintOrderChildItems() const;
+ void addChild(QSGItem *);
+ void removeChild(QSGItem *);
+ void siblingOrderChanged();
+
+ class InitializationState {
+ public:
+ QSGItem *getFocusScope(QSGItem *item);
+ void clear();
+ void clear(QSGItem *focusScope);
+ private:
+ QSGItem *focusScope;
+ };
+ void initCanvas(InitializationState *, QSGCanvas *);
+
+ QSGItem *subFocusItem;
+
+ QTransform canvasToItemTransform() const;
+ QTransform itemToCanvasTransform() const;
+ void itemToParentTransform(QTransform &) const;
+
+ qreal x;
+ qreal y;
+ qreal width;
+ qreal height;
+ qreal implicitWidth;
+ qreal implicitHeight;
+
+ qreal z;
+ qreal scale;
+ qreal rotation;
+ qreal opacity;
+
+ QSGLayoutMirroringAttached* attachedLayoutDirection;
+
+ Qt::MouseButtons acceptedMouseButtons;
+ Qt::InputMethodHints imHints;
+
+ virtual qreal getImplicitWidth() const;
+ virtual qreal getImplicitHeight() const;
+ virtual void implicitWidthChanged();
+ virtual void implicitHeightChanged();
+
+ void resolveLayoutMirror();
+ void setImplicitLayoutMirror(bool mirror, bool inherit);
+ void setLayoutMirror(bool mirror);
+ bool isMirrored() const {
+ return effectiveLayoutMirror;
+ }
+
+ QPointF computeTransformOrigin() const;
+ QList<QSGTransform *> transforms;
+ virtual void transformChanged();
+
+ QSGItemKeyFilter *keyHandler;
+ void deliverKeyEvent(QKeyEvent *);
+ void deliverInputMethodEvent(QInputMethodEvent *);
+ void deliverFocusEvent(QFocusEvent *);
+ void deliverMouseEvent(QGraphicsSceneMouseEvent *);
+ void deliverWheelEvent(QGraphicsSceneWheelEvent *);
+ void deliverTouchEvent(QTouchEvent *);
+ void deliverHoverEvent(QGraphicsSceneHoverEvent *);
+
+ bool calcEffectiveVisible() const;
+ void setEffectiveVisibleRecur(bool);
+ bool calcEffectiveEnable() const;
+ void setEffectiveEnableRecur(bool);
+
+ // XXX todo
+ enum DirtyType {
+ TransformOrigin = 0x00000001,
+ Transform = 0x00000002,
+ BasicTransform = 0x00000004,
+ Position = 0x00000008,
+ Size = 0x00000010,
+
+ ZValue = 0x00000020,
+ Content = 0x00000040,
+ Smooth = 0x00000080,
+ OpacityValue = 0x00000100,
+ ChildrenChanged = 0x00000200,
+ ChildrenStackingChanged = 0x00000400,
+ ParentChanged = 0x00000800,
+
+ Clip = 0x00001000,
+ Canvas = 0x00002000,
+
+ EffectReference = 0x00008000,
+ Visible = 0x00010000,
+ HideReference = 0x00020000,
+ // When you add an attribute here, don't forget to update
+ // dirtyToString()
+
+ TransformUpdateMask = TransformOrigin | Transform | BasicTransform | Position | Size | Canvas,
+ ComplexTransformUpdateMask = Transform | Canvas,
+ ContentUpdateMask = Size | Content | Smooth | Canvas,
+ ChildrenUpdateMask = ChildrenChanged | ChildrenStackingChanged | EffectReference | Canvas,
+
+ };
+ quint32 dirtyAttributes;
+ QString dirtyToString() const;
+ void dirty(DirtyType);
+ void addToDirtyList();
+ void removeFromDirtyList();
+ QSGItem *nextDirtyItem;
+ QSGItem**prevDirtyItem;
+
+ inline QSGTransformNode *itemNode();
+ inline QSGNode *childContainerNode();
+
+ /*
+ QSGNode order is:
+ - itemNode
+ - (opacityNode)
+ - (clipNode)
+ - (effectNode)
+ - groupNode
+ */
+
+ QSGTransformNode *itemNodeInstance;
+ QSGOpacityNode *opacityNode;
+ QSGDefaultClipNode *clipNode;
+ QSGRootNode *rootNode;
+ QSGNode *groupNode;
+ QSGNode *paintNode;
+ int paintNodeIndex;
+
+ virtual QSGTransformNode *createTransformNode();
+
+ // A reference from an effect item means that this item is used by the effect, so
+ // it should insert a root node.
+ void refFromEffectItem(bool hide);
+ void derefFromEffectItem(bool unhide);
+ int effectRefCount;
+ int hideRefCount;
+
+ void itemChange(QSGItem::ItemChange, const QSGItem::ItemChangeData &);
+
+ virtual void mirrorChange() {}
+
+ static qint64 consistentTime;
+ static void setConsistentTime(qint64 t);
+ static void start(QElapsedTimer &);
+ static qint64 elapsed(QElapsedTimer &);
+ static qint64 restart(QElapsedTimer &);
+};
+
+/*
+ Key filters can be installed on a QSGItem, but not removed. Currently they
+ are only used by attached objects (which are only destroyed on Item
+ destruction), so this isn't a problem. If in future this becomes any form
+ of public API, they will have to support removal too.
+*/
+class QSGItemKeyFilter
+{
+public:
+ QSGItemKeyFilter(QSGItem * = 0);
+ virtual ~QSGItemKeyFilter();
+
+ virtual void keyPressed(QKeyEvent *event, bool post);
+ virtual void keyReleased(QKeyEvent *event, bool post);
+ virtual void inputMethodEvent(QInputMethodEvent *event, bool post);
+ virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+ virtual void componentComplete();
+
+ bool m_processPost;
+
+private:
+ QSGItemKeyFilter *m_next;
+};
+
+class QSGKeyNavigationAttachedPrivate : public QObjectPrivate
+{
+public:
+ QSGKeyNavigationAttachedPrivate()
+ : QObjectPrivate(),
+ left(0), right(0), up(0), down(0), tab(0), backtab(0),
+ leftSet(false), rightSet(false), upSet(false), downSet(false),
+ tabSet(false), backtabSet(false) {}
+
+ QSGItem *left;
+ QSGItem *right;
+ QSGItem *up;
+ QSGItem *down;
+ QSGItem *tab;
+ QSGItem *backtab;
+ bool leftSet : 1;
+ bool rightSet : 1;
+ bool upSet : 1;
+ bool downSet : 1;
+ bool tabSet : 1;
+ bool backtabSet : 1;
+};
+
+class QSGKeyNavigationAttached : public QObject, public QSGItemKeyFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGKeyNavigationAttached)
+
+ Q_PROPERTY(QSGItem *left READ left WRITE setLeft NOTIFY leftChanged)
+ Q_PROPERTY(QSGItem *right READ right WRITE setRight NOTIFY rightChanged)
+ Q_PROPERTY(QSGItem *up READ up WRITE setUp NOTIFY upChanged)
+ Q_PROPERTY(QSGItem *down READ down WRITE setDown NOTIFY downChanged)
+ Q_PROPERTY(QSGItem *tab READ tab WRITE setTab NOTIFY tabChanged)
+ Q_PROPERTY(QSGItem *backtab READ backtab WRITE setBacktab NOTIFY backtabChanged)
+ Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
+
+ Q_ENUMS(Priority)
+
+public:
+ QSGKeyNavigationAttached(QObject * = 0);
+
+ QSGItem *left() const;
+ void setLeft(QSGItem *);
+ QSGItem *right() const;
+ void setRight(QSGItem *);
+ QSGItem *up() const;
+ void setUp(QSGItem *);
+ QSGItem *down() const;
+ void setDown(QSGItem *);
+ QSGItem *tab() const;
+ void setTab(QSGItem *);
+ QSGItem *backtab() const;
+ void setBacktab(QSGItem *);
+
+ enum Priority { BeforeItem, AfterItem };
+ Priority priority() const;
+ void setPriority(Priority);
+
+ static QSGKeyNavigationAttached *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void leftChanged();
+ void rightChanged();
+ void upChanged();
+ void downChanged();
+ void tabChanged();
+ void backtabChanged();
+ void priorityChanged();
+
+private:
+ virtual void keyPressed(QKeyEvent *event, bool post);
+ virtual void keyReleased(QKeyEvent *event, bool post);
+ void setFocusNavigation(QSGItem *currentItem, const char *dir);
+};
+
+class QSGLayoutMirroringAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled RESET resetEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool childrenInherit READ childrenInherit WRITE setChildrenInherit NOTIFY childrenInheritChanged)
+
+public:
+ explicit QSGLayoutMirroringAttached(QObject *parent = 0);
+
+ bool enabled() const;
+ void setEnabled(bool);
+ void resetEnabled();
+
+ bool childrenInherit() const;
+ void setChildrenInherit(bool);
+
+ static QSGLayoutMirroringAttached *qmlAttachedProperties(QObject *);
+Q_SIGNALS:
+ void enabledChanged();
+ void childrenInheritChanged();
+private:
+ friend class QSGItemPrivate;
+ QSGItemPrivate *itemPrivate;
+};
+
+class QSGKeysAttachedPrivate : public QObjectPrivate
+{
+public:
+ QSGKeysAttachedPrivate()
+ : QObjectPrivate(), inPress(false), inRelease(false)
+ , inIM(false), enabled(true), imeItem(0), item(0)
+ {}
+
+ bool isConnected(const char *signalName);
+
+ //loop detection
+ bool inPress:1;
+ bool inRelease:1;
+ bool inIM:1;
+
+ bool enabled : 1;
+
+ QSGItem *imeItem;
+ QList<QSGItem *> targets;
+ QSGItem *item;
+};
+
+class QSGKeysAttached : public QObject, public QSGItemKeyFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGKeysAttached)
+
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QSGItem> forwardTo READ forwardTo)
+ Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
+
+ Q_ENUMS(Priority)
+
+public:
+ QSGKeysAttached(QObject *parent=0);
+ ~QSGKeysAttached();
+
+ bool enabled() const { Q_D(const QSGKeysAttached); return d->enabled; }
+ void setEnabled(bool enabled) {
+ Q_D(QSGKeysAttached);
+ if (enabled != d->enabled) {
+ d->enabled = enabled;
+ emit enabledChanged();
+ }
+ }
+
+ enum Priority { BeforeItem, AfterItem};
+ Priority priority() const;
+ void setPriority(Priority);
+
+ QDeclarativeListProperty<QSGItem> forwardTo() {
+ Q_D(QSGKeysAttached);
+ return QDeclarativeListProperty<QSGItem>(this, d->targets);
+ }
+
+ virtual void componentComplete();
+
+ static QSGKeysAttached *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void enabledChanged();
+ void priorityChanged();
+ void pressed(QSGKeyEvent *event);
+ void released(QSGKeyEvent *event);
+ void digit0Pressed(QSGKeyEvent *event);
+ void digit1Pressed(QSGKeyEvent *event);
+ void digit2Pressed(QSGKeyEvent *event);
+ void digit3Pressed(QSGKeyEvent *event);
+ void digit4Pressed(QSGKeyEvent *event);
+ void digit5Pressed(QSGKeyEvent *event);
+ void digit6Pressed(QSGKeyEvent *event);
+ void digit7Pressed(QSGKeyEvent *event);
+ void digit8Pressed(QSGKeyEvent *event);
+ void digit9Pressed(QSGKeyEvent *event);
+
+ void leftPressed(QSGKeyEvent *event);
+ void rightPressed(QSGKeyEvent *event);
+ void upPressed(QSGKeyEvent *event);
+ void downPressed(QSGKeyEvent *event);
+ void tabPressed(QSGKeyEvent *event);
+ void backtabPressed(QSGKeyEvent *event);
+
+ void asteriskPressed(QSGKeyEvent *event);
+ void numberSignPressed(QSGKeyEvent *event);
+ void escapePressed(QSGKeyEvent *event);
+ void returnPressed(QSGKeyEvent *event);
+ void enterPressed(QSGKeyEvent *event);
+ void deletePressed(QSGKeyEvent *event);
+ void spacePressed(QSGKeyEvent *event);
+ void backPressed(QSGKeyEvent *event);
+ void cancelPressed(QSGKeyEvent *event);
+ void selectPressed(QSGKeyEvent *event);
+ void yesPressed(QSGKeyEvent *event);
+ void noPressed(QSGKeyEvent *event);
+ void context1Pressed(QSGKeyEvent *event);
+ void context2Pressed(QSGKeyEvent *event);
+ void context3Pressed(QSGKeyEvent *event);
+ void context4Pressed(QSGKeyEvent *event);
+ void callPressed(QSGKeyEvent *event);
+ void hangupPressed(QSGKeyEvent *event);
+ void flipPressed(QSGKeyEvent *event);
+ void menuPressed(QSGKeyEvent *event);
+ void volumeUpPressed(QSGKeyEvent *event);
+ void volumeDownPressed(QSGKeyEvent *event);
+
+private:
+ virtual void keyPressed(QKeyEvent *event, bool post);
+ virtual void keyReleased(QKeyEvent *event, bool post);
+ virtual void inputMethodEvent(QInputMethodEvent *, bool post);
+ virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+ const QByteArray keyToSignal(int key) {
+ QByteArray keySignal;
+ if (key >= Qt::Key_0 && key <= Qt::Key_9) {
+ keySignal = "digit0Pressed";
+ keySignal[5] = '0' + (key - Qt::Key_0);
+ } else {
+ int i = 0;
+ while (sigMap[i].key && sigMap[i].key != key)
+ ++i;
+ keySignal = sigMap[i].sig;
+ }
+ return keySignal;
+ }
+
+ struct SigMap {
+ int key;
+ const char *sig;
+ };
+
+ static const SigMap sigMap[];
+};
+
+QSGTransformNode *QSGItemPrivate::itemNode()
+{
+ if (!itemNodeInstance) {
+ itemNodeInstance = createTransformNode();
+#ifdef QML_RUNTIME_TESTING
+ Q_Q(QSGItem);
+ itemNodeInstance->description = QString::fromLatin1("QSGItem(%1)").arg(QString::fromLatin1(q->metaObject()->className()));
+#endif
+ }
+ return itemNodeInstance;
+}
+
+QSGNode *QSGItemPrivate::childContainerNode()
+{
+ if (!groupNode) {
+ groupNode = new QSGNode();
+ if (rootNode)
+ rootNode->appendChildNode(groupNode);
+ else if (clipNode)
+ clipNode->appendChildNode(groupNode);
+ else if (opacityNode)
+ opacityNode->appendChildNode(groupNode);
+ else
+ itemNode()->appendChildNode(groupNode);
+#ifdef QML_RUNTIME_TESTING
+ groupNode->description = QLatin1String("group");
+#endif
+ }
+ return groupNode;
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGItemPrivate::ChangeTypes);
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGKeysAttached)
+QML_DECLARE_TYPEINFO(QSGKeysAttached, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QSGKeyNavigationAttached)
+QML_DECLARE_TYPEINFO(QSGKeyNavigationAttached, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QSGLayoutMirroringAttached)
+QML_DECLARE_TYPEINFO(QSGLayoutMirroringAttached, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QSGITEM_P_H
diff --git a/src/declarative/items/qsgitemchangelistener_p.h b/src/declarative/items/qsgitemchangelistener_p.h
new file mode 100644
index 0000000000..3b4018a772
--- /dev/null
+++ b/src/declarative/items/qsgitemchangelistener_p.h
@@ -0,0 +1,82 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGITEMCHANGELISTENER_P_H
+#define QSGITEMCHANGELISTENER_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 <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRectF;
+class QSGItem;
+class QSGAnchorsPrivate;
+class QSGItemChangeListener
+{
+public:
+ virtual void itemGeometryChanged(QSGItem *, const QRectF &, const QRectF &) {}
+ virtual void itemSiblingOrderChanged(QSGItem *) {}
+ virtual void itemVisibilityChanged(QSGItem *) {}
+ virtual void itemOpacityChanged(QSGItem *) {}
+ virtual void itemDestroyed(QSGItem *) {}
+ virtual void itemChildAdded(QSGItem *, QSGItem *) {}
+ virtual void itemChildRemoved(QSGItem *, QSGItem *) {}
+ virtual void itemParentChanged(QSGItem *, QSGItem *) {}
+ virtual void itemRotationChanged(QSGItem *) {}
+
+ virtual QSGAnchorsPrivate *anchorPrivate() { return 0; }
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGITEMCHANGELISTENER_P_H
diff --git a/src/declarative/items/qsgitemsmodule.cpp b/src/declarative/items/qsgitemsmodule.cpp
new file mode 100644
index 0000000000..aa74ff6bc5
--- /dev/null
+++ b/src/declarative/items/qsgitemsmodule.cpp
@@ -0,0 +1,205 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgitemsmodule_p.h"
+
+#include "qsgitem.h"
+#include "qsgitem_p.h"
+#include "qsgevents_p_p.h"
+#include "qsgrectangle_p.h"
+#include "qsgfocusscope_p.h"
+#include "qsgtext_p.h"
+#include "qsgtextinput_p.h"
+#include "qsgtextedit_p.h"
+#include "qsgimage_p.h"
+#include "qsgborderimage_p.h"
+#include "qsgscalegrid_p_p.h"
+#include "qsgmousearea_p.h"
+#include "qsgpincharea_p.h"
+#include "qsgflickable_p.h"
+#include "qsgflickable_p_p.h"
+#include "qsglistview_p.h"
+#include "qsgvisualitemmodel_p.h"
+#include "qsggridview_p.h"
+#include "qsgpathview_p.h"
+#include <private/qdeclarativepath_p.h>
+#include "qsgpositioners_p.h"
+#include "qsgrepeater_p.h"
+#include "qsgloader_p.h"
+#include "qsganimatedimage_p.h"
+#include "qsgflipable_p.h"
+#include "qsgtranslate_p.h"
+#include "qsgstateoperations_p.h"
+#include "qsganimation_p.h"
+#include <private/qsgshadereffectitem_p.h>
+#include <private/qsgshadereffectsource_p.h>
+//#include "private/qsgpincharea_p.h"
+
+static QDeclarativePrivate::AutoParentResult qsgitem_autoParent(QObject *obj, QObject *parent)
+{
+ QSGItem *item = qobject_cast<QSGItem *>(obj);
+ if (!item)
+ return QDeclarativePrivate::IncompatibleObject;
+
+ QSGItem *parentItem = qobject_cast<QSGItem *>(parent);
+ if (!parentItem)
+ return QDeclarativePrivate::IncompatibleParent;
+
+ item->setParentItem(parentItem);
+ return QDeclarativePrivate::Parented;
+}
+
+static void qt_sgitems_defineModule(const char *uri, int major, int minor)
+{
+ QDeclarativePrivate::RegisterAutoParent autoparent = { 0, &qsgitem_autoParent };
+ QDeclarativePrivate::qmlregister(QDeclarativePrivate::AutoParentRegistration, &autoparent);
+
+#ifdef QT_NO_MOVIE
+ qmlRegisterTypeNotAvailable(uri,major,minor,"AnimatedImage", qApp->translate("QSGAnimatedImage","Qt was built without support for QMovie"));
+#else
+ qmlRegisterType<QSGAnimatedImage>(uri,major,minor,"AnimatedImage");
+#endif
+ qmlRegisterType<QSGBorderImage>(uri,major,minor,"BorderImage");
+ qmlRegisterType<QSGColumn>(uri,major,minor,"Column");
+ qmlRegisterType<QSGDrag>(uri,major,minor,"Drag");
+ qmlRegisterType<QSGFlickable>(uri,major,minor,"Flickable");
+ qmlRegisterType<QSGFlipable>(uri,major,minor,"Flipable");
+ qmlRegisterType<QSGFlow>(uri,major,minor,"Flow");
+// qmlRegisterType<QDeclarativeFocusPanel>(uri,major,minor,"FocusPanel");
+ qmlRegisterType<QSGFocusScope>(uri,major,minor,"FocusScope");
+ qmlRegisterType<QSGGradient>(uri,major,minor,"Gradient");
+ qmlRegisterType<QSGGradientStop>(uri,major,minor,"GradientStop");
+ qmlRegisterType<QSGGrid>(uri,major,minor,"Grid");
+ qmlRegisterType<QSGGridView>(uri,major,minor,"GridView");
+ qmlRegisterType<QSGImage>(uri,major,minor,"Image");
+ qmlRegisterType<QSGItem>(uri,major,minor,"Item");
+ qmlRegisterType<QSGListView>(uri,major,minor,"ListView");
+ qmlRegisterType<QSGLoader>(uri,major,minor,"Loader");
+ qmlRegisterType<QSGMouseArea>(uri,major,minor,"MouseArea");
+ qmlRegisterType<QDeclarativePath>(uri,major,minor,"Path");
+ qmlRegisterType<QDeclarativePathAttribute>(uri,major,minor,"PathAttribute");
+ qmlRegisterType<QDeclarativePathCubic>(uri,major,minor,"PathCubic");
+ qmlRegisterType<QDeclarativePathLine>(uri,major,minor,"PathLine");
+ qmlRegisterType<QDeclarativePathPercent>(uri,major,minor,"PathPercent");
+ qmlRegisterType<QDeclarativePathQuad>(uri,major,minor,"PathQuad");
+ qmlRegisterType<QSGPathView>(uri,major,minor,"PathView");
+#ifndef QT_NO_VALIDATOR
+ qmlRegisterType<QIntValidator>(uri,major,minor,"IntValidator");
+ qmlRegisterType<QDoubleValidator>(uri,major,minor,"DoubleValidator");
+ qmlRegisterType<QRegExpValidator>(uri,major,minor,"RegExpValidator");
+#endif
+ qmlRegisterType<QSGRectangle>(uri,major,minor,"Rectangle");
+ qmlRegisterType<QSGRepeater>(uri,major,minor,"Repeater");
+ qmlRegisterType<QSGRow>(uri,major,minor,"Row");
+ qmlRegisterType<QSGTranslate>(uri,major,minor,"Translate");
+ qmlRegisterType<QSGRotation>(uri,major,minor,"Rotation");
+ qmlRegisterType<QSGScale>(uri,major,minor,"Scale");
+ qmlRegisterType<QSGText>(uri,major,minor,"Text");
+ qmlRegisterType<QSGTextEdit>(uri,major,minor,"TextEdit");
+ qmlRegisterType<QSGTextInput>(uri,major,minor,"TextInput");
+ qmlRegisterType<QSGViewSection>(uri,major,minor,"ViewSection");
+ qmlRegisterType<QSGVisualDataModel>(uri,major,minor,"VisualDataModel");
+ qmlRegisterType<QSGVisualItemModel>(uri,major,minor,"VisualItemModel");
+
+ qmlRegisterType<QSGAnchors>();
+ qmlRegisterType<QSGKeyEvent>();
+ qmlRegisterType<QSGMouseEvent>();
+ qmlRegisterType<QSGTransform>();
+ qmlRegisterType<QDeclarativePathElement>();
+ qmlRegisterType<QDeclarativeCurve>();
+ qmlRegisterType<QSGScaleGrid>();
+#ifndef QT_NO_VALIDATOR
+ qmlRegisterType<QValidator>();
+#endif
+ qmlRegisterType<QSGVisualModel>();
+#ifndef QT_NO_ACTION
+ qmlRegisterType<QAction>();
+#endif
+ qmlRegisterType<QSGPen>();
+ qmlRegisterType<QSGFlickableVisibleArea>();
+ qRegisterMetaType<QSGAnchorLine>("QSGAnchorLine");
+
+ qmlRegisterUncreatableType<QSGKeyNavigationAttached>(uri,major,minor,"KeyNavigation",QSGKeyNavigationAttached::tr("KeyNavigation is only available via attached properties"));
+ qmlRegisterUncreatableType<QSGKeysAttached>(uri,major,minor,"Keys",QSGKeysAttached::tr("Keys is only available via attached properties"));
+ qmlRegisterUncreatableType<QSGLayoutMirroringAttached>(uri,major,minor,"LayoutMirroring", QSGLayoutMirroringAttached::tr("LayoutMirroring is only available via attached properties"));
+
+ qmlRegisterType<QSGPinchArea>(uri,major,minor,"PinchArea");
+ qmlRegisterType<QSGPinch>(uri,major,minor,"Pinch");
+ qmlRegisterType<QSGPinchEvent>();
+
+ qmlRegisterType<QSGShaderEffectItem>("QtQuick", 2, 0, "ShaderEffectItem");
+ qmlRegisterType<QSGShaderEffectSource>("QtQuick", 2, 0, "ShaderEffectSource");
+ qmlRegisterUncreatableType<QSGShaderEffectMesh>("QtQuick", 2, 0, "ShaderEffectMesh", QSGShaderEffectMesh::tr("Cannot create instance of abstract class ShaderEffectMesh."));
+ qmlRegisterType<QSGGridMesh>("QtQuick", 2, 0, "GridMesh");
+
+ qmlRegisterUncreatableType<QSGPaintedItem>("QtQuick", 2, 0, "PaintedItem", QSGPaintedItem::tr("Cannot create instance of abstract class PaintedItem"));
+
+ qmlRegisterType<QSGParentChange>(uri, major, minor,"ParentChange");
+ qmlRegisterType<QSGAnchorChanges>(uri, major, minor,"AnchorChanges");
+ qmlRegisterType<QSGAnchorSet>();
+ qmlRegisterType<QSGAnchorAnimation>(uri, major, minor,"AnchorAnimation");
+ qmlRegisterType<QSGParentAnimation>(uri, major, minor,"ParentAnimation");
+}
+
+void QSGItemsModule::defineModule()
+{
+ static bool initialized = false;
+ if (initialized)
+ return;
+ initialized = true;
+
+ // XXX todo - Remove before final integration...
+ QByteArray mode = qgetenv("QMLSCENE_IMPORT_NAME");
+ QByteArray name = "QtQuick";
+ int majorVersion = 2;
+ int minorVersion = 0;
+ if (mode == "quick1") {
+ majorVersion = 1;
+ } else if (mode == "qt") {
+ name = "Qt";
+ majorVersion = 4;
+ minorVersion = 7;
+ }
+
+ qt_sgitems_defineModule(name, majorVersion, minorVersion);
+}
+
diff --git a/src/declarative/items/qsgitemsmodule_p.h b/src/declarative/items/qsgitemsmodule_p.h
new file mode 100644
index 0000000000..2d8a971c22
--- /dev/null
+++ b/src/declarative/items/qsgitemsmodule_p.h
@@ -0,0 +1,65 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGITEMSMODULE_P_H
+#define QSGITEMSMODULE_P_H
+
+#include <qdeclarative.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItemsModule
+{
+public:
+ static void defineModule();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGITEMSMODULE_P_H
+
diff --git a/src/declarative/items/qsglistview.cpp b/src/declarative/items/qsglistview.cpp
new file mode 100644
index 0000000000..496fdaf4cc
--- /dev/null
+++ b/src/declarative/items/qsglistview.cpp
@@ -0,0 +1,3032 @@
+// Commit: ce38c6e3a9b7eb336cbd9cd1e9520a5000c8f8ac
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsglistview_p.h"
+#include "qsgflickable_p_p.h"
+#include "qsgvisualitemmodel_p.h"
+
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qevent.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <private/qdeclarativesmoothedanimation_p_p.h>
+#include <private/qlistmodelinterface_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QSGViewSection::setProperty(const QString &property)
+{
+ if (property != m_property) {
+ m_property = property;
+ emit propertyChanged();
+ }
+}
+
+void QSGViewSection::setCriteria(QSGViewSection::SectionCriteria criteria)
+{
+ if (criteria != m_criteria) {
+ m_criteria = criteria;
+ emit criteriaChanged();
+ }
+}
+
+void QSGViewSection::setDelegate(QDeclarativeComponent *delegate)
+{
+ if (delegate != m_delegate) {
+ m_delegate = delegate;
+ emit delegateChanged();
+ }
+}
+
+QString QSGViewSection::sectionString(const QString &value)
+{
+ if (m_criteria == FirstCharacter)
+ return value.isEmpty() ? QString() : value.at(0);
+ else
+ return value;
+}
+
+//----------------------------------------------------------------------------
+
+class FxListItemSG
+{
+public:
+ FxListItemSG(QSGItem *i, QSGListView *v) : item(i), section(0), view(v) {
+ attached = static_cast<QSGListViewAttached*>(qmlAttachedPropertiesObject<QSGListView>(item));
+ if (attached)
+ attached->setView(view);
+ }
+ ~FxListItemSG() {}
+ qreal position() const {
+ if (section) {
+ if (view->orientation() == QSGListView::Vertical)
+ return section->y();
+ else
+ return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section->width()-section->x() : section->x());
+ } else {
+ return itemPosition();
+ }
+ }
+ qreal itemPosition() const {
+ if (view->orientation() == QSGListView::Vertical)
+ return item->y();
+ else
+ return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-item->x() : item->x());
+ }
+ qreal size() const {
+ if (section)
+ return (view->orientation() == QSGListView::Vertical ? item->height()+section->height() : item->width()+section->width());
+ else
+ return (view->orientation() == QSGListView::Vertical ? item->height() : item->width());
+ }
+ qreal itemSize() const {
+ return (view->orientation() == QSGListView::Vertical ? item->height() : item->width());
+ }
+ qreal sectionSize() const {
+ if (section)
+ return (view->orientation() == QSGListView::Vertical ? section->height() : section->width());
+ return 0.0;
+ }
+ qreal endPosition() const {
+ if (view->orientation() == QSGListView::Vertical) {
+ return item->y() + (item->height() >= 1.0 ? item->height() : 1) - 1;
+ } else {
+ return (view->effectiveLayoutDirection() == Qt::RightToLeft
+ ? -item->width()-item->x() + (item->width() >= 1.0 ? item->width() : 1)
+ : item->x() + (item->width() >= 1.0 ? item->width() : 1)) - 1;
+ }
+ }
+ void setPosition(qreal pos) {
+ if (view->orientation() == QSGListView::Vertical) {
+ if (section) {
+ section->setY(pos);
+ pos += section->height();
+ }
+ item->setY(pos);
+ } else {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
+ if (section) {
+ section->setX(-section->width()-pos);
+ pos += section->width();
+ }
+ item->setX(-item->width()-pos);
+ } else {
+ if (section) {
+ section->setX(pos);
+ pos += section->width();
+ }
+ item->setX(pos);
+ }
+ }
+ }
+ void setSize(qreal size) {
+ if (view->orientation() == QSGListView::Vertical)
+ item->setHeight(size);
+ else
+ item->setWidth(size);
+ }
+ bool contains(qreal x, qreal y) const {
+ return (x >= item->x() && x < item->x() + item->width() &&
+ y >= item->y() && y < item->y() + item->height());
+ }
+
+ QSGItem *item;
+ QSGItem *section;
+ QSGListView *view;
+ QSGListViewAttached *attached;
+ int index;
+};
+
+//----------------------------------------------------------------------------
+
+class QSGListViewPrivate : public QSGFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QSGListView)
+
+public:
+ QSGListViewPrivate()
+ : currentItem(0), orient(QSGListView::Vertical), layoutDirection(Qt::LeftToRight)
+ , visiblePos(0), visibleIndex(0)
+ , averageSize(100.0), currentIndex(-1), requestedIndex(-1)
+ , itemCount(0), highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightComponent(0), highlight(0), trackedItem(0)
+ , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0)
+ , sectionCriteria(0), spacing(0.0)
+ , highlightMoveSpeed(400), highlightMoveDuration(-1)
+ , highlightResizeSpeed(400), highlightResizeDuration(-1), highlightRange(QSGListView::NoHighlightRange)
+ , snapMode(QSGListView::NoSnap), overshootDist(0.0)
+ , footerComponent(0), footer(0), headerComponent(0), header(0)
+ , bufferMode(BufferBefore | BufferAfter)
+ , ownModel(false), wrap(false), autoHighlight(true), haveHighlightRange(false)
+ , correctFlick(false), inFlickCorrection(false), lazyRelease(false)
+ , deferredRelease(false), layoutScheduled(false), currentIndexCleared(false)
+ , inViewportMoved(false)
+ , highlightRangeStartValid(false), highlightRangeEndValid(false)
+ , minExtentDirty(true), maxExtentDirty(true)
+ {}
+
+ void init();
+ void clear();
+ FxListItemSG *createItem(int modelIndex);
+ void releaseItem(FxListItemSG *item);
+
+ FxListItemSG *visibleItem(int modelIndex) const {
+ if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
+ for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
+ FxListItemSG *item = visibleItems.at(i);
+ if (item->index == modelIndex)
+ return item;
+ }
+ }
+ return 0;
+ }
+
+ FxListItemSG *firstVisibleItem() const {
+ const qreal pos = isRightToLeft() ? -position()-size() : position();
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *item = visibleItems.at(i);
+ if (item->index != -1 && item->endPosition() > pos)
+ return item;
+ }
+ return visibleItems.count() ? visibleItems.first() : 0;
+ }
+
+ FxListItemSG *nextVisibleItem() const {
+ const qreal pos = isRightToLeft() ? -position()-size() : position();
+ bool foundFirst = false;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *item = visibleItems.at(i);
+ if (item->index != -1) {
+ if (foundFirst)
+ return item;
+ else if (item->position() < pos && item->endPosition() > pos)
+ foundFirst = true;
+ }
+ }
+ return 0;
+ }
+
+ // Returns the item before modelIndex, if created.
+ // May return an item marked for removal.
+ FxListItemSG *itemBefore(int modelIndex) const {
+ if (modelIndex < visibleIndex)
+ return 0;
+ int idx = 1;
+ int lastIndex = -1;
+ while (idx < visibleItems.count()) {
+ FxListItemSG *item = visibleItems.at(idx);
+ if (item->index != -1)
+ lastIndex = item->index;
+ if (item->index == modelIndex)
+ return visibleItems.at(idx-1);
+ ++idx;
+ }
+ if (lastIndex == modelIndex-1)
+ return visibleItems.last();
+ return 0;
+ }
+
+ void regenerate() {
+ Q_Q(QSGListView);
+ if (q->isComponentComplete()) {
+ if (header) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ header->item->setParentItem(0);
+ header->item->deleteLater();
+ delete header;
+ header = 0;
+ }
+ if (footer) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ footer->item->setParentItem(0);
+ footer->item->deleteLater();
+ delete footer;
+ footer = 0;
+ }
+ updateHeader();
+ updateFooter();
+ clear();
+ setPosition(0);
+ q->refill();
+ updateCurrent(currentIndex);
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QSGListView);
+ regenerate();
+ emit q->effectiveLayoutDirectionChanged();
+ }
+
+ bool isRightToLeft() const {
+ Q_Q(const QSGListView);
+ return orient == QSGListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
+ }
+
+ qreal position() const {
+ Q_Q(const QSGListView);
+ return orient == QSGListView::Vertical ? q->contentY() : q->contentX();
+ }
+ void setPosition(qreal pos) {
+ Q_Q(QSGListView);
+ if (orient == QSGListView::Vertical) {
+ q->QSGFlickable::setContentY(pos);
+ } else {
+ if (isRightToLeft())
+ q->QSGFlickable::setContentX(-pos-size());
+ else
+ q->QSGFlickable::setContentX(pos);
+ }
+ }
+ qreal size() const {
+ Q_Q(const QSGListView);
+ return orient == QSGListView::Vertical ? q->height() : q->width();
+ }
+
+ qreal originPosition() const {
+ qreal pos = 0;
+ if (!visibleItems.isEmpty()) {
+ pos = (*visibleItems.constBegin())->position();
+ if (visibleIndex > 0)
+ pos -= visibleIndex * (averageSize + spacing);
+ }
+ return pos;
+ }
+
+ qreal lastPosition() const {
+ qreal pos = 0;
+ if (!visibleItems.isEmpty()) {
+ int invisibleCount = visibleItems.count() - visibleIndex;
+ for (int i = visibleItems.count()-1; i >= 0; --i) {
+ if (visibleItems.at(i)->index != -1) {
+ invisibleCount = model->count() - visibleItems.at(i)->index - 1;
+ break;
+ }
+ }
+ pos = (*(--visibleItems.constEnd()))->endPosition() + invisibleCount * (averageSize + spacing);
+ } else if (model && model->count()) {
+ pos = model->count() * averageSize + (model->count()-1) * spacing;
+ }
+ return pos;
+ }
+
+ qreal startPosition() const {
+ return isRightToLeft() ? -lastPosition()-1 : originPosition();
+ }
+
+ qreal endPosition() const {
+ return isRightToLeft() ? -originPosition()-1 : lastPosition();
+ }
+
+ qreal positionAt(int modelIndex) const {
+ if (FxListItemSG *item = visibleItem(modelIndex))
+ return item->position();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int count = visibleIndex - modelIndex;
+ qreal cs = 0;
+ if (modelIndex == currentIndex && currentItem) {
+ cs = currentItem->size() + spacing;
+ --count;
+ }
+ return (*visibleItems.constBegin())->position() - count * (averageSize + spacing) - cs;
+ } else {
+ int idx = visibleItems.count() - 1;
+ while (idx >= 0 && visibleItems.at(idx)->index == -1)
+ --idx;
+ if (idx < 0)
+ idx = visibleIndex;
+ else
+ idx = visibleItems.at(idx)->index;
+ int count = modelIndex - idx - 1;
+ return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing) + 1;
+ }
+ }
+ return 0;
+ }
+
+ qreal endPositionAt(int modelIndex) const {
+ if (FxListItemSG *item = visibleItem(modelIndex))
+ return item->endPosition();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int count = visibleIndex - modelIndex;
+ return (*visibleItems.constBegin())->position() - (count - 1) * (averageSize + spacing) - spacing - 1;
+ } else {
+ int idx = visibleItems.count() - 1;
+ while (idx >= 0 && visibleItems.at(idx)->index == -1)
+ --idx;
+ if (idx < 0)
+ idx = visibleIndex;
+ else
+ idx = visibleItems.at(idx)->index;
+ int count = modelIndex - idx - 1;
+ return (*(--visibleItems.constEnd()))->endPosition() + count * (averageSize + spacing);
+ }
+ }
+ return 0;
+ }
+
+ QString sectionAt(int modelIndex) {
+ if (FxListItemSG *item = visibleItem(modelIndex))
+ return item->attached->section();
+
+ QString section;
+ if (sectionCriteria) {
+ QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
+ section = sectionCriteria->sectionString(propValue);
+ }
+
+ return section;
+ }
+
+ bool isValid() const {
+ return model && model->count() && model->isValid();
+ }
+
+ qreal snapPosAt(qreal pos) {
+ if (FxListItemSG *snapItem = snapItemAt(pos))
+ return snapItem->position();
+ if (visibleItems.count()) {
+ qreal firstPos = visibleItems.first()->position();
+ qreal endPos = visibleItems.last()->position();
+ if (pos < firstPos) {
+ return firstPos - qRound((firstPos - pos) / averageSize) * averageSize;
+ } else if (pos > endPos)
+ return endPos + qRound((pos - endPos) / averageSize) * averageSize;
+ }
+ return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition();
+ }
+
+ FxListItemSG *snapItemAt(qreal pos) {
+ FxListItemSG *snapItem = 0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *item = visibleItems[i];
+ if (item->index == -1)
+ continue;
+ qreal itemTop = item->position();
+ if (highlight && itemTop >= pos && item->endPosition() <= pos + highlight->size() - 1)
+ return item;
+ if (itemTop+item->size()/2 >= pos && itemTop-item->size()/2 < pos)
+ snapItem = item;
+ }
+ return snapItem;
+ }
+
+ int lastVisibleIndex() const {
+ int lastIndex = -1;
+ for (int i = visibleItems.count()-1; i >= 0; --i) {
+ FxListItemSG *listItem = visibleItems.at(i);
+ if (listItem->index != -1) {
+ lastIndex = listItem->index;
+ break;
+ }
+ }
+ return lastIndex;
+ }
+
+ // map a model index to visibleItems index.
+ int mapFromModel(int modelIndex) const {
+ if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
+ return -1;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *listItem = visibleItems.at(i);
+ if (listItem->index == modelIndex)
+ return i;
+ if (listItem->index > modelIndex)
+ return -1;
+ }
+ return -1; // Not in visibleList
+ }
+
+ void updateViewport() {
+ Q_Q(QSGListView);
+ if (orient == QSGListView::Vertical) {
+ q->setContentHeight(endPosition() - startPosition() + 1);
+ } else {
+ q->setContentWidth(endPosition() - startPosition() + 1);
+ }
+ }
+
+ void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
+ Q_Q(QSGListView);
+ QSGFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
+ if (!q->isComponentComplete())
+ return;
+ if (item != contentItem && (!highlight || item != highlight->item)) {
+ if ((orient == QSGListView::Vertical && newGeometry.height() != oldGeometry.height())
+ || (orient == QSGListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
+ scheduleLayout();
+ }
+ }
+ if ((header && header->item == item) || (footer && footer->item == item)) {
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ }
+ if (currentItem && currentItem->item == item)
+ updateHighlight();
+ if (trackedItem && trackedItem->item == item)
+ q->trackedPositionChanged();
+ }
+
+ // for debugging only
+ void checkVisible() const {
+ int skip = 0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItemSG *listItem = visibleItems.at(i);
+ if (listItem->index == -1) {
+ ++skip;
+ } else if (listItem->index != visibleIndex + i - skip) {
+ qFatal("index %d %d %d", visibleIndex, i, listItem->index);
+ }
+ }
+ }
+
+ void refill(qreal from, qreal to, bool doBuffer = false);
+ void scheduleLayout();
+ void layout();
+ void updateUnrequestedIndexes();
+ void updateUnrequestedPositions();
+ void updateTrackedItem();
+ void createHighlight();
+ void updateHighlight();
+ void createSection(FxListItemSG *);
+ void updateSections();
+ void updateCurrentSection();
+ void updateCurrent(int);
+ void updateAverage();
+ void updateHeader();
+ void updateFooter();
+ void fixupPosition();
+ void positionViewAtIndex(int index, int mode);
+ virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
+ virtual void flick(QSGFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
+
+ QDeclarativeGuard<QSGVisualModel> model;
+ QVariant modelVariant;
+ QList<FxListItemSG*> visibleItems;
+ QHash<QSGItem*,int> unrequestedItems;
+ FxListItemSG *currentItem;
+ QSGListView::Orientation orient;
+ Qt::LayoutDirection layoutDirection;
+ qreal visiblePos;
+ int visibleIndex;
+ qreal averageSize;
+ int currentIndex;
+ int requestedIndex;
+ int itemCount;
+ qreal highlightRangeStart;
+ qreal highlightRangeEnd;
+ QDeclarativeComponent *highlightComponent;
+ FxListItemSG *highlight;
+ FxListItemSG *trackedItem;
+ enum MovementReason { Other, SetIndex, Mouse };
+ MovementReason moveReason;
+ int buffer;
+ QSmoothedAnimation *highlightPosAnimator;
+ QSmoothedAnimation *highlightSizeAnimator;
+ QSGViewSection *sectionCriteria;
+ QString currentSection;
+ static const int sectionCacheSize = 4;
+ QSGItem *sectionCache[sectionCacheSize];
+ qreal spacing;
+ qreal highlightMoveSpeed;
+ int highlightMoveDuration;
+ qreal highlightResizeSpeed;
+ int highlightResizeDuration;
+ QSGListView::HighlightRangeMode highlightRange;
+ QSGListView::SnapMode snapMode;
+ qreal overshootDist;
+ QDeclarativeComponent *footerComponent;
+ FxListItemSG *footer;
+ QDeclarativeComponent *headerComponent;
+ FxListItemSG *header;
+ enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
+ int bufferMode;
+ mutable qreal minExtent;
+ mutable qreal maxExtent;
+
+ bool ownModel : 1;
+ bool wrap : 1;
+ bool autoHighlight : 1;
+ bool haveHighlightRange : 1;
+ bool correctFlick : 1;
+ bool inFlickCorrection : 1;
+ bool lazyRelease : 1;
+ bool deferredRelease : 1;
+ bool layoutScheduled : 1;
+ bool currentIndexCleared : 1;
+ bool inViewportMoved : 1;
+ bool highlightRangeStartValid : 1;
+ bool highlightRangeEndValid : 1;
+ mutable bool minExtentDirty : 1;
+ mutable bool maxExtentDirty : 1;
+};
+
+void QSGListViewPrivate::init()
+{
+ Q_Q(QSGListView);
+ q->setFlag(QSGItem::ItemIsFocusScope);
+ addItemChangeListener(this, Geometry);
+ QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
+ q->setFlickableDirection(QSGFlickable::VerticalFlick);
+ ::memset(sectionCache, 0, sizeof(QSGItem*) * sectionCacheSize);
+}
+
+void QSGListViewPrivate::clear()
+{
+ timeline.clear();
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ for (int i = 0; i < sectionCacheSize; ++i) {
+ delete sectionCache[i];
+ sectionCache[i] = 0;
+ }
+ visiblePos = header ? header->size() : 0;
+ visibleIndex = 0;
+ releaseItem(currentItem);
+ currentItem = 0;
+ createHighlight();
+ trackedItem = 0;
+ minExtentDirty = true;
+ maxExtentDirty = true;
+ itemCount = 0;
+}
+
+FxListItemSG *QSGListViewPrivate::createItem(int modelIndex)
+{
+ Q_Q(QSGListView);
+ // create object
+ requestedIndex = modelIndex;
+ FxListItemSG *listItem = 0;
+ if (QSGItem *item = model->item(modelIndex, false)) {
+ listItem = new FxListItemSG(item, q);
+ listItem->index = modelIndex;
+ // initialise attached properties
+ if (sectionCriteria) {
+ QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
+ listItem->attached->m_section = sectionCriteria->sectionString(propValue);
+ if (modelIndex > 0) {
+ if (FxListItemSG *item = itemBefore(modelIndex))
+ listItem->attached->m_prevSection = item->attached->section();
+ else
+ listItem->attached->m_prevSection = sectionAt(modelIndex-1);
+ }
+ if (modelIndex < model->count()-1) {
+ if (FxListItemSG *item = visibleItem(modelIndex+1))
+ listItem->attached->m_nextSection = item->attached->section();
+ else
+ listItem->attached->m_nextSection = sectionAt(modelIndex+1);
+ }
+ }
+ if (model->completePending()) {
+ // complete
+ listItem->item->setZ(1);
+ listItem->item->setParentItem(q->contentItem());
+ model->completeItem();
+ } else {
+ listItem->item->setParentItem(q->contentItem());
+ }
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ if (sectionCriteria && sectionCriteria->delegate()) {
+ if (listItem->attached->m_prevSection != listItem->attached->m_section)
+ createSection(listItem);
+ }
+ unrequestedItems.remove(listItem->item);
+ }
+ requestedIndex = -1;
+
+ return listItem;
+}
+
+void QSGListViewPrivate::releaseItem(FxListItemSG *item)
+{
+ Q_Q(QSGListView);
+ if (!item || !model)
+ return;
+ if (trackedItem == item)
+ trackedItem = 0;
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item->item);
+ itemPrivate->removeItemChangeListener(this, QSGItemPrivate::Geometry);
+ if (model->release(item->item) == 0) {
+ // item was not destroyed, and we no longer reference it.
+ unrequestedItems.insert(item->item, model->indexOf(item->item, q));
+ }
+ if (item->section) {
+ int i = 0;
+ do {
+ if (!sectionCache[i]) {
+ sectionCache[i] = item->section;
+ sectionCache[i]->setVisible(false);
+ item->section = 0;
+ break;
+ }
+ ++i;
+ } while (i < sectionCacheSize);
+ delete item->section;
+ }
+ delete item;
+}
+
+void QSGListViewPrivate::refill(qreal from, qreal to, bool doBuffer)
+{
+ Q_Q(QSGListView);
+ if (!isValid() || !q->isComponentComplete())
+ return;
+ itemCount = model->count();
+ qreal bufferFrom = from - buffer;
+ qreal bufferTo = to + buffer;
+ qreal fillFrom = from;
+ qreal fillTo = to;
+ if (doBuffer && (bufferMode & BufferAfter))
+ fillTo = bufferTo;
+ if (doBuffer && (bufferMode & BufferBefore))
+ fillFrom = bufferFrom;
+
+ int modelIndex = visibleIndex;
+ qreal itemEnd = visiblePos-1;
+ if (!visibleItems.isEmpty()) {
+ visiblePos = (*visibleItems.constBegin())->position();
+ itemEnd = (*(--visibleItems.constEnd()))->endPosition() + spacing;
+ int i = visibleItems.count() - 1;
+ while (i > 0 && visibleItems.at(i)->index == -1)
+ --i;
+ if (visibleItems.at(i)->index != -1)
+ modelIndex = visibleItems.at(i)->index + 1;
+ }
+
+ bool changed = false;
+ FxListItemSG *item = 0;
+ qreal pos = itemEnd + 1;
+ while (modelIndex < model->count() && pos <= fillTo) {
+// qDebug() << "refill: append item" << modelIndex << "pos" << pos;
+ if (!(item = createItem(modelIndex)))
+ break;
+ item->setPosition(pos);
+ pos += item->size() + spacing;
+ visibleItems.append(item);
+ ++modelIndex;
+ changed = true;
+ if (doBuffer) // never buffer more than one item per frame
+ break;
+ }
+ while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos-1 >= fillFrom) {
+// qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
+ if (!(item = createItem(visibleIndex-1)))
+ break;
+ --visibleIndex;
+ visiblePos -= item->size() + spacing;
+ item->setPosition(visiblePos);
+ visibleItems.prepend(item);
+ changed = true;
+ if (doBuffer) // never buffer more than one item per frame
+ break;
+ }
+
+ if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
+ while (visibleItems.count() > 1 && (item = visibleItems.first()) && item->endPosition() < bufferFrom) {
+ if (item->attached->delayRemove())
+ break;
+// qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
+ if (item->index != -1)
+ visibleIndex++;
+ visibleItems.removeFirst();
+ releaseItem(item);
+ changed = true;
+ }
+ while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
+ if (item->attached->delayRemove())
+ break;
+// qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
+ visibleItems.removeLast();
+ releaseItem(item);
+ changed = true;
+ }
+ deferredRelease = false;
+ } else {
+ deferredRelease = true;
+ }
+ if (changed) {
+ minExtentDirty = true;
+ maxExtentDirty = true;
+ if (visibleItems.count())
+ visiblePos = (*visibleItems.constBegin())->position();
+ updateAverage();
+ if (currentIndex >= 0 && currentItem && !visibleItem(currentIndex)) {
+ currentItem->setPosition(positionAt(currentIndex));
+ updateHighlight();
+ }
+
+ if (sectionCriteria)
+ updateCurrentSection();
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ updateViewport();
+ updateUnrequestedPositions();
+ } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
+ refill(from, to, true);
+ }
+ lazyRelease = false;
+}
+
+void QSGListViewPrivate::scheduleLayout()
+{
+ Q_Q(QSGListView);
+ if (!layoutScheduled) {
+ layoutScheduled = true;
+ q->polish();
+ }
+}
+
+void QSGListViewPrivate::layout()
+{
+ Q_Q(QSGListView);
+ layoutScheduled = false;
+ if (!isValid() && !visibleItems.count()) {
+ clear();
+ setPosition(0);
+ return;
+ }
+ if (!visibleItems.isEmpty()) {
+ bool fixedCurrent = currentItem && visibleItems.first()->item == currentItem->item;
+ qreal sum = visibleItems.first()->size();
+ qreal pos = visibleItems.first()->position() + visibleItems.first()->size() + spacing;
+ for (int i=1; i < visibleItems.count(); ++i) {
+ FxListItemSG *item = visibleItems.at(i);
+ item->setPosition(pos);
+ pos += item->size() + spacing;
+ sum += item->size();
+ fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
+ }
+ averageSize = qRound(sum / visibleItems.count());
+ // move current item if it is not a visible item.
+ if (currentIndex >= 0 && currentItem && !fixedCurrent)
+ currentItem->setPosition(positionAt(currentIndex));
+ }
+ q->refill();
+ minExtentDirty = true;
+ maxExtentDirty = true;
+ updateHighlight();
+ if (!q->isMoving() && !q->isFlicking()) {
+ fixupPosition();
+ q->refill();
+ }
+ if (header)
+ updateHeader();
+ if (footer)
+ updateFooter();
+ updateViewport();
+}
+
+void QSGListViewPrivate::updateUnrequestedIndexes()
+{
+ Q_Q(QSGListView);
+ QHash<QSGItem*,int>::iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
+ *it = model->indexOf(it.key(), q);
+}
+
+void QSGListViewPrivate::updateUnrequestedPositions()
+{
+ Q_Q(QSGListView);
+ if (unrequestedItems.count()) {
+ qreal pos = position();
+ QHash<QSGItem*,int>::const_iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
+ QSGItem *item = it.key();
+ if (orient == QSGListView::Vertical) {
+ if (item->y() + item->height() > pos && item->y() < pos + q->height())
+ item->setY(positionAt(*it));
+ } else {
+ if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
+ if (isRightToLeft())
+ item->setX(-positionAt(*it)-item->width());
+ else
+ item->setX(positionAt(*it));
+ }
+ }
+ }
+ }
+}
+
+void QSGListViewPrivate::updateTrackedItem()
+{
+ Q_Q(QSGListView);
+ FxListItemSG *item = currentItem;
+ if (highlight)
+ item = highlight;
+ trackedItem = item;
+ if (trackedItem)
+ q->trackedPositionChanged();
+}
+
+void QSGListViewPrivate::createHighlight()
+{
+ Q_Q(QSGListView);
+ bool changed = false;
+ if (highlight) {
+ if (trackedItem == highlight)
+ trackedItem = 0;
+ delete highlight->item;
+ delete highlight;
+ highlight = 0;
+ delete highlightPosAnimator;
+ delete highlightSizeAnimator;
+ highlightPosAnimator = 0;
+ highlightSizeAnimator = 0;
+ changed = true;
+ }
+
+ if (currentItem) {
+ QSGItem *item = 0;
+ if (highlightComponent) {
+ QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = highlightComponent->create(highlightContext);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(highlightContext, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete highlightContext;
+ }
+ } else {
+ item = new QSGItem;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ highlight = new FxListItemSG(item, q);
+ if (currentItem && autoHighlight) {
+ if (orient == QSGListView::Vertical) {
+ highlight->item->setHeight(currentItem->item->height());
+ } else {
+ highlight->item->setWidth(currentItem->item->width());
+ }
+ highlight->setPosition(currentItem->itemPosition());
+ }
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ const QLatin1String posProp(orient == QSGListView::Vertical ? "y" : "x");
+ highlightPosAnimator = new QSmoothedAnimation(q);
+ highlightPosAnimator->target = QDeclarativeProperty(highlight->item, posProp);
+ highlightPosAnimator->velocity = highlightMoveSpeed;
+ highlightPosAnimator->userDuration = highlightMoveDuration;
+ const QLatin1String sizeProp(orient == QSGListView::Vertical ? "height" : "width");
+ highlightSizeAnimator = new QSmoothedAnimation(q);
+ highlightSizeAnimator->velocity = highlightResizeSpeed;
+ highlightSizeAnimator->userDuration = highlightResizeDuration;
+ highlightSizeAnimator->target = QDeclarativeProperty(highlight->item, sizeProp);
+ if (autoHighlight) {
+ highlightPosAnimator->restart();
+ highlightSizeAnimator->restart();
+ }
+ changed = true;
+ }
+ }
+ if (changed)
+ emit q->highlightItemChanged();
+}
+
+void QSGListViewPrivate::updateHighlight()
+{
+ if ((!currentItem && highlight) || (currentItem && !highlight))
+ createHighlight();
+ if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) {
+ // auto-update highlight
+ highlightPosAnimator->to = isRightToLeft()
+ ? -currentItem->itemPosition()-currentItem->itemSize()
+ : currentItem->itemPosition();
+ highlightSizeAnimator->to = currentItem->itemSize();
+ if (orient == QSGListView::Vertical) {
+ if (highlight->item->width() == 0)
+ highlight->item->setWidth(currentItem->item->width());
+ } else {
+ if (highlight->item->height() == 0)
+ highlight->item->setHeight(currentItem->item->height());
+ }
+ highlightPosAnimator->restart();
+ highlightSizeAnimator->restart();
+ }
+ updateTrackedItem();
+}
+
+void QSGListViewPrivate::createSection(FxListItemSG *listItem)
+{
+ Q_Q(QSGListView);
+ if (!sectionCriteria || !sectionCriteria->delegate())
+ return;
+ if (listItem->attached->m_prevSection != listItem->attached->m_section) {
+ if (!listItem->section) {
+ qreal pos = listItem->position();
+ int i = sectionCacheSize-1;
+ while (i >= 0 && !sectionCache[i])
+ --i;
+ if (i >= 0) {
+ listItem->section = sectionCache[i];
+ sectionCache[i] = 0;
+ listItem->section->setVisible(true);
+ QDeclarativeContext *context = QDeclarativeEngine::contextForObject(listItem->section)->parentContext();
+ context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
+ } else {
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
+ QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ listItem->section = qobject_cast<QSGItem *>(nobj);
+ if (!listItem->section) {
+ delete nobj;
+ } else {
+ listItem->section->setZ(1);
+ QDeclarative_setParent_noEvent(listItem->section, q->contentItem());
+ listItem->section->setParentItem(q->contentItem());
+ }
+ } else {
+ delete context;
+ }
+ sectionCriteria->delegate()->completeCreate();
+ }
+ listItem->setPosition(pos);
+ } else {
+ QDeclarativeContext *context = QDeclarativeEngine::contextForObject(listItem->section)->parentContext();
+ context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
+ }
+ } else if (listItem->section) {
+ qreal pos = listItem->position();
+ int i = 0;
+ do {
+ if (!sectionCache[i]) {
+ sectionCache[i] = listItem->section;
+ sectionCache[i]->setVisible(false);
+ listItem->section = 0;
+ return;
+ }
+ ++i;
+ } while (i < sectionCacheSize);
+ delete listItem->section;
+ listItem->section = 0;
+ listItem->setPosition(pos);
+ }
+}
+
+void QSGListViewPrivate::updateSections()
+{
+ if (sectionCriteria && !visibleItems.isEmpty()) {
+ QString prevSection;
+ if (visibleIndex > 0)
+ prevSection = sectionAt(visibleIndex-1);
+ QSGListViewAttached *prevAtt = 0;
+ int idx = -1;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ QSGListViewAttached *attached = visibleItems.at(i)->attached;
+ attached->setPrevSection(prevSection);
+ if (visibleItems.at(i)->index != -1) {
+ QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property());
+ attached->setSection(sectionCriteria->sectionString(propValue));
+ idx = visibleItems.at(i)->index;
+ }
+ createSection(visibleItems.at(i));
+ if (prevAtt)
+ prevAtt->setNextSection(attached->section());
+ prevSection = attached->section();
+ prevAtt = attached;
+ }
+ if (prevAtt) {
+ if (idx > 0 && idx < model->count()-1)
+ prevAtt->setNextSection(sectionAt(idx+1));
+ else
+ prevAtt->setNextSection(QString());
+ }
+ }
+}
+
+void QSGListViewPrivate::updateCurrentSection()
+{
+ Q_Q(QSGListView);
+ if (!sectionCriteria || visibleItems.isEmpty()) {
+ if (!currentSection.isEmpty()) {
+ currentSection.clear();
+ emit q->currentSectionChanged();
+ }
+ return;
+ }
+ int index = 0;
+ while (index < visibleItems.count() && visibleItems.at(index)->endPosition() < position())
+ ++index;
+
+ QString newSection = currentSection;
+ if (index < visibleItems.count())
+ newSection = visibleItems.at(index)->attached->section();
+ else
+ newSection = visibleItems.first()->attached->section();
+ if (newSection != currentSection) {
+ currentSection = newSection;
+ emit q->currentSectionChanged();
+ }
+}
+
+void QSGListViewPrivate::updateCurrent(int modelIndex)
+{
+ Q_Q(QSGListView);
+ if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
+ if (currentItem) {
+ currentItem->attached->setIsCurrentItem(false);
+ releaseItem(currentItem);
+ currentItem = 0;
+ currentIndex = modelIndex;
+ emit q->currentIndexChanged();
+ updateHighlight();
+ } else if (currentIndex != modelIndex) {
+ currentIndex = modelIndex;
+ emit q->currentIndexChanged();
+ }
+ return;
+ }
+
+ if (currentItem && currentIndex == modelIndex) {
+ updateHighlight();
+ return;
+ }
+ FxListItemSG *oldCurrentItem = currentItem;
+ currentIndex = modelIndex;
+ currentItem = createItem(modelIndex);
+ if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
+ oldCurrentItem->attached->setIsCurrentItem(false);
+ if (currentItem) {
+ if (modelIndex == visibleIndex - 1 && visibleItems.count()) {
+ // We can calculate exact postion in this case
+ currentItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing);
+ } else {
+ // Create current item now and position as best we can.
+ // Its position will be corrected when it becomes visible.
+ currentItem->setPosition(positionAt(modelIndex));
+ }
+ currentItem->item->setFocus(true);
+ currentItem->attached->setIsCurrentItem(true);
+ // Avoid showing section delegate twice. We still need the section heading so that
+ // currentItem positioning works correctly.
+ // This is slightly sub-optimal, but section heading caching minimizes the impact.
+ if (currentItem->section)
+ currentItem->section->setVisible(false);
+ if (visibleItems.isEmpty())
+ averageSize = currentItem->size();
+ }
+ updateHighlight();
+ emit q->currentIndexChanged();
+ // Release the old current item
+ releaseItem(oldCurrentItem);
+}
+
+void QSGListViewPrivate::updateAverage()
+{
+ if (!visibleItems.count())
+ return;
+ qreal sum = 0.0;
+ for (int i = 0; i < visibleItems.count(); ++i)
+ sum += visibleItems.at(i)->size();
+ averageSize = qRound(sum / visibleItems.count());
+}
+
+void QSGListViewPrivate::updateFooter()
+{
+ Q_Q(QSGListView);
+ if (!footer && footerComponent) {
+ QSGItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = footerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZ(1);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ footer = new FxListItemSG(item, q);
+ }
+ }
+ if (footer) {
+ if (visibleItems.count()) {
+ qreal endPos = lastPosition() + 1;
+ if (lastVisibleIndex() == model->count()-1) {
+ footer->setPosition(endPos);
+ } else {
+ qreal visiblePos = position() + q->height();
+ if (endPos <= visiblePos || footer->position() < endPos)
+ footer->setPosition(endPos);
+ }
+ } else {
+ footer->setPosition(visiblePos);
+ }
+ }
+}
+
+void QSGListViewPrivate::updateHeader()
+{
+ Q_Q(QSGListView);
+ if (!header && headerComponent) {
+ QSGItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = headerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZ(1);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ header = new FxListItemSG(item, q);
+ }
+ }
+ if (header) {
+ if (visibleItems.count()) {
+ qreal startPos = originPosition();
+ if (visibleIndex == 0) {
+ header->setPosition(startPos - header->size());
+ } else {
+ if (position() <= startPos || header->position() > startPos - header->size())
+ header->setPosition(startPos - header->size());
+ }
+ } else {
+ if (itemCount == 0)
+ visiblePos = header->size();
+ header->setPosition(0);
+ }
+ }
+}
+
+void QSGListViewPrivate::fixupPosition()
+{
+ if ((haveHighlightRange && highlightRange == QSGListView::StrictlyEnforceRange)
+ || snapMode != QSGListView::NoSnap)
+ moveReason = Other;
+ if (orient == QSGListView::Vertical)
+ fixupY();
+ else
+ fixupX();
+}
+
+void QSGListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
+{
+ if ((orient == QSGListView::Horizontal && &data == &vData)
+ || (orient == QSGListView::Vertical && &data == &hData))
+ return;
+
+ correctFlick = false;
+ fixupMode = moveReason == Mouse ? fixupMode : Immediate;
+
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal viewPos;
+ if (isRightToLeft()) {
+ // Handle Right-To-Left exceptions
+ viewPos = -position()-size();
+ highlightStart = highlightRangeStartValid ? size() - highlightRangeEnd : highlightRangeStart;
+ highlightEnd = highlightRangeEndValid ? size() - highlightRangeStart : highlightRangeEnd;
+ } else {
+ viewPos = position();
+ highlightStart = highlightRangeStart;
+ highlightEnd = highlightRangeEnd;
+ }
+
+ if (currentItem && haveHighlightRange && highlightRange == QSGListView::StrictlyEnforceRange
+ && moveReason != QSGListViewPrivate::SetIndex) {
+ updateHighlight();
+ qreal pos = currentItem->itemPosition();
+ if (viewPos < pos + currentItem->itemSize() - highlightEnd)
+ viewPos = pos + currentItem->itemSize() - highlightEnd;
+ if (viewPos > pos - highlightStart)
+ viewPos = pos - highlightStart;
+ if (isRightToLeft())
+ viewPos = -viewPos-size();
+
+ timeline.reset(data.move);
+ if (viewPos != position()) {
+ if (fixupMode != Immediate) {
+ timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+ data.fixingUp = true;
+ } else {
+ timeline.set(data.move, -viewPos);
+ }
+ }
+ vTime = timeline.time();
+ } else if (snapMode != QSGListView::NoSnap && moveReason != QSGListViewPrivate::SetIndex) {
+ qreal tempPosition = isRightToLeft() ? -position()-size() : position();
+ FxListItemSG *topItem = snapItemAt(tempPosition+highlightStart);
+ FxListItemSG *bottomItem = snapItemAt(tempPosition+highlightEnd);
+ qreal pos;
+ bool isInBounds = -position() > maxExtent && -position() < minExtent;
+ if (topItem && isInBounds) {
+ if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+header->size()/2) {
+ pos = isRightToLeft() ? - header->position() + highlightStart - size() : header->position() - highlightStart;
+ } else {
+ if (isRightToLeft())
+ pos = qMax(qMin(-topItem->position() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(topItem->position() - highlightStart, -maxExtent), -minExtent);
+ }
+ } else if (bottomItem && isInBounds) {
+ if (isRightToLeft())
+ pos = qMax(qMin(-bottomItem->position() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(bottomItem->position() - highlightStart, -maxExtent), -minExtent);
+ } else {
+ QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
+ return;
+ }
+
+ qreal dist = qAbs(data.move + pos);
+ if (dist > 0) {
+ timeline.reset(data.move);
+ if (fixupMode != Immediate) {
+ timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+ data.fixingUp = true;
+ } else {
+ timeline.set(data.move, -pos);
+ }
+ vTime = timeline.time();
+ }
+ } else {
+ QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
+ }
+ fixupMode = Normal;
+}
+
+void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
+{
+ Q_Q(QSGListView);
+
+ data.fixingUp = false;
+ moveReason = Mouse;
+ if ((!haveHighlightRange || highlightRange != QSGListView::StrictlyEnforceRange) && snapMode == QSGListView::NoSnap) {
+ correctFlick = true;
+ QSGFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
+ return;
+ }
+ qreal maxDistance = 0;
+ qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
+ // -ve velocity means list is moving up/left
+ if (velocity > 0) {
+ if (data.move.value() < minExtent) {
+ if (snapMode == QSGListView::SnapOneItem) {
+ if (FxListItemSG *item = isRightToLeft() ? nextVisibleItem() : firstVisibleItem())
+ maxDistance = qAbs(item->position() + dataValue);
+ } else {
+ maxDistance = qAbs(minExtent - data.move.value());
+ }
+ }
+ if (snapMode == QSGListView::NoSnap && highlightRange != QSGListView::StrictlyEnforceRange)
+ data.flickTarget = minExtent;
+ } else {
+ if (data.move.value() > maxExtent) {
+ if (snapMode == QSGListView::SnapOneItem) {
+ if (FxListItemSG *item = isRightToLeft() ? firstVisibleItem() : nextVisibleItem())
+ maxDistance = qAbs(item->position() + dataValue);
+ } else {
+ maxDistance = qAbs(maxExtent - data.move.value());
+ }
+ }
+ if (snapMode == QSGListView::NoSnap && highlightRange != QSGListView::StrictlyEnforceRange)
+ data.flickTarget = maxExtent;
+ }
+ bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
+ qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+ if (maxDistance > 0 || overShoot) {
+ // These modes require the list to stop exactly on an item boundary.
+ // The initial flick will estimate the boundary to stop on.
+ // Since list items can have variable sizes, the boundary will be
+ // reevaluated and adjusted as we approach the boundary.
+ qreal v = velocity;
+ if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
+ if (v < 0)
+ v = -maxVelocity;
+ else
+ v = maxVelocity;
+ }
+ if (!flickingHorizontally && !flickingVertically) {
+ // the initial flick - estimate boundary
+ qreal accel = deceleration;
+ qreal v2 = v * v;
+ overshootDist = 0.0;
+ // + averageSize/4 to encourage moving at least one item in the flick direction
+ qreal dist = v2 / (accel * 2.0) + averageSize/4;
+ if (maxDistance > 0)
+ dist = qMin(dist, maxDistance);
+ if (v > 0)
+ dist = -dist;
+ if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QSGListView::SnapOneItem) {
+ qreal distTemp = isRightToLeft() ? -dist : dist;
+ data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+ data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
+ if (overShoot) {
+ if (data.flickTarget >= minExtent) {
+ overshootDist = overShootDistance(v, vSize);
+ data.flickTarget += overshootDist;
+ } else if (data.flickTarget <= maxExtent) {
+ overshootDist = overShootDistance(v, vSize);
+ data.flickTarget -= overshootDist;
+ }
+ }
+ qreal adjDist = -data.flickTarget + data.move.value();
+ if (qAbs(adjDist) > qAbs(dist)) {
+ // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
+ qreal adjv2 = accel * 2.0f * qAbs(adjDist);
+ if (adjv2 > v2) {
+ v2 = adjv2;
+ v = qSqrt(v2);
+ if (dist > 0)
+ v = -v;
+ }
+ }
+ dist = adjDist;
+ accel = v2 / (2.0f * qAbs(dist));
+ } else if (overShoot) {
+ data.flickTarget = data.move.value() - dist;
+ if (data.flickTarget >= minExtent) {
+ overshootDist = overShootDistance(v, vSize);
+ data.flickTarget += overshootDist;
+ } else if (data.flickTarget <= maxExtent) {
+ overshootDist = overShootDistance(v, vSize);
+ data.flickTarget -= overshootDist;
+ }
+ }
+ timeline.reset(data.move);
+ timeline.accel(data.move, v, accel, maxDistance + overshootDist);
+ timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
+ if (!flickingHorizontally && q->xflick()) {
+ flickingHorizontally = true;
+ emit q->flickingChanged();
+ emit q->flickingHorizontallyChanged();
+ emit q->flickStarted();
+ }
+ if (!flickingVertically && q->yflick()) {
+ flickingVertically = true;
+ emit q->flickingChanged();
+ emit q->flickingVerticallyChanged();
+ emit q->flickStarted();
+ }
+ correctFlick = true;
+ } else {
+ // reevaluate the target boundary.
+ qreal newtarget = data.flickTarget;
+ if (snapMode != QSGListView::NoSnap || highlightRange == QSGListView::StrictlyEnforceRange) {
+ qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
+ newtarget = -snapPosAt(-(tempFlickTarget - highlightStart)) + highlightStart;
+ newtarget = isRightToLeft() ? -newtarget+size() : newtarget;
+ }
+ if (velocity < 0 && newtarget <= maxExtent)
+ newtarget = maxExtent - overshootDist;
+ else if (velocity > 0 && newtarget >= minExtent)
+ newtarget = minExtent + overshootDist;
+ if (newtarget == data.flickTarget) { // boundary unchanged - nothing to do
+ if (qAbs(velocity) < MinimumFlickVelocity)
+ correctFlick = false;
+ return;
+ }
+ data.flickTarget = newtarget;
+ qreal dist = -newtarget + data.move.value();
+ if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
+ correctFlick = false;
+ timeline.reset(data.move);
+ fixup(data, minExtent, maxExtent);
+ return;
+ }
+ timeline.reset(data.move);
+ timeline.accelDistance(data.move, v, -dist);
+ timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
+ }
+ } else {
+ correctFlick = false;
+ timeline.reset(data.move);
+ fixup(data, minExtent, maxExtent);
+ }
+}
+
+//----------------------------------------------------------------------------
+
+QSGListView::QSGListView(QSGItem *parent)
+ : QSGFlickable(*(new QSGListViewPrivate), parent)
+{
+ Q_D(QSGListView);
+ d->init();
+}
+
+QSGListView::~QSGListView()
+{
+ Q_D(QSGListView);
+ d->clear();
+ if (d->ownModel)
+ delete d->model;
+ delete d->header;
+ delete d->footer;
+}
+
+QVariant QSGListView::model() const
+{
+ Q_D(const QSGListView);
+ return d->modelVariant;
+}
+
+void QSGListView::setModel(const QVariant &model)
+{
+ Q_D(QSGListView);
+ if (d->modelVariant == model)
+ return;
+ if (d->model) {
+ disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ disconnect(d->model, SIGNAL(itemsChanged(int,int)), this, SLOT(itemsChanged(int,int)));
+ disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ }
+ d->clear();
+ QSGVisualModel *oldModel = d->model;
+ d->model = 0;
+ d->setPosition(0);
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QSGVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QSGVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete oldModel;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this), this);
+ d->ownModel = true;
+ } else {
+ d->model = oldModel;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ dataModel->setModel(model);
+ }
+ if (d->model) {
+ d->bufferMode = QSGListViewPrivate::BufferBefore | QSGListViewPrivate::BufferAfter;
+ if (isComponentComplete()) {
+ updateSections();
+ refill();
+ if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
+ setCurrentIndex(0);
+ } else {
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->position());
+ d->updateTrackedItem();
+ }
+ }
+ d->updateViewport();
+ }
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ connect(d->model, SIGNAL(itemsChanged(int,int)), this, SLOT(itemsChanged(int,int)));
+ connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ emit countChanged();
+ }
+ emit modelChanged();
+}
+
+QDeclarativeComponent *QSGListView::delegate() const
+{
+ Q_D(const QSGListView);
+ if (d->model) {
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QSGListView::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QSGListView);
+ if (delegate == this->delegate())
+ return;
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model)) {
+ dataModel->setDelegate(delegate);
+ if (isComponentComplete()) {
+ for (int i = 0; i < d->visibleItems.count(); ++i)
+ d->releaseItem(d->visibleItems.at(i));
+ d->visibleItems.clear();
+ d->releaseItem(d->currentItem);
+ d->currentItem = 0;
+ updateSections();
+ refill();
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->position());
+ d->updateTrackedItem();
+ }
+ d->updateViewport();
+ }
+ }
+ emit delegateChanged();
+}
+
+int QSGListView::currentIndex() const
+{
+ Q_D(const QSGListView);
+ return d->currentIndex;
+}
+
+void QSGListView::setCurrentIndex(int index)
+{
+ Q_D(QSGListView);
+ if (d->requestedIndex >= 0) // currently creating item
+ return;
+ d->currentIndexCleared = (index == -1);
+ if (index == d->currentIndex)
+ return;
+ if (isComponentComplete() && d->isValid()) {
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ d->updateCurrent(index);
+ } else if (d->currentIndex != index) {
+ d->currentIndex = index;
+ emit currentIndexChanged();
+ }
+}
+
+QSGItem *QSGListView::currentItem()
+{
+ Q_D(QSGListView);
+ if (!d->currentItem)
+ return 0;
+ return d->currentItem->item;
+}
+
+QSGItem *QSGListView::highlightItem()
+{
+ Q_D(QSGListView);
+ if (!d->highlight)
+ return 0;
+ return d->highlight->item;
+}
+
+int QSGListView::count() const
+{
+ Q_D(const QSGListView);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+QDeclarativeComponent *QSGListView::highlight() const
+{
+ Q_D(const QSGListView);
+ return d->highlightComponent;
+}
+
+void QSGListView::setHighlight(QDeclarativeComponent *highlight)
+{
+ Q_D(QSGListView);
+ if (highlight != d->highlightComponent) {
+ d->highlightComponent = highlight;
+ d->createHighlight();
+ if (d->currentItem)
+ d->updateHighlight();
+ emit highlightChanged();
+ }
+}
+
+bool QSGListView::highlightFollowsCurrentItem() const
+{
+ Q_D(const QSGListView);
+ return d->autoHighlight;
+}
+
+void QSGListView::setHighlightFollowsCurrentItem(bool autoHighlight)
+{
+ Q_D(QSGListView);
+ if (d->autoHighlight != autoHighlight) {
+ d->autoHighlight = autoHighlight;
+ if (autoHighlight) {
+ d->updateHighlight();
+ } else {
+ if (d->highlightPosAnimator)
+ d->highlightPosAnimator->stop();
+ if (d->highlightSizeAnimator)
+ d->highlightSizeAnimator->stop();
+ }
+ emit highlightFollowsCurrentItemChanged();
+ }
+}
+
+//###Possibly rename these properties, since they are very useful even without a highlight?
+qreal QSGListView::preferredHighlightBegin() const
+{
+ Q_D(const QSGListView);
+ return d->highlightRangeStart;
+}
+
+void QSGListView::setPreferredHighlightBegin(qreal start)
+{
+ Q_D(QSGListView);
+ d->highlightRangeStartValid = true;
+ if (d->highlightRangeStart == start)
+ return;
+ d->highlightRangeStart = start;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightBeginChanged();
+}
+
+void QSGListView::resetPreferredHighlightBegin()
+{
+ Q_D(QSGListView);
+ d->highlightRangeStartValid = false;
+ if (d->highlightRangeStart == 0)
+ return;
+ d->highlightRangeStart = 0;
+ emit preferredHighlightBeginChanged();
+}
+
+qreal QSGListView::preferredHighlightEnd() const
+{
+ Q_D(const QSGListView);
+ return d->highlightRangeEnd;
+}
+
+void QSGListView::setPreferredHighlightEnd(qreal end)
+{
+ Q_D(QSGListView);
+ d->highlightRangeEndValid = true;
+ if (d->highlightRangeEnd == end)
+ return;
+ d->highlightRangeEnd = end;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightEndChanged();
+}
+
+void QSGListView::resetPreferredHighlightEnd()
+{
+ Q_D(QSGListView);
+ d->highlightRangeEndValid = false;
+ if (d->highlightRangeEnd == 0)
+ return;
+ d->highlightRangeEnd = 0;
+ emit preferredHighlightEndChanged();
+}
+
+QSGListView::HighlightRangeMode QSGListView::highlightRangeMode() const
+{
+ Q_D(const QSGListView);
+ return d->highlightRange;
+}
+
+void QSGListView::setHighlightRangeMode(HighlightRangeMode mode)
+{
+ Q_D(QSGListView);
+ if (d->highlightRange == mode)
+ return;
+ d->highlightRange = mode;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit highlightRangeModeChanged();
+}
+
+qreal QSGListView::spacing() const
+{
+ Q_D(const QSGListView);
+ return d->spacing;
+}
+
+void QSGListView::setSpacing(qreal spacing)
+{
+ Q_D(QSGListView);
+ if (spacing != d->spacing) {
+ d->spacing = spacing;
+ d->layout();
+ emit spacingChanged();
+ }
+}
+
+QSGListView::Orientation QSGListView::orientation() const
+{
+ Q_D(const QSGListView);
+ return d->orient;
+}
+
+void QSGListView::setOrientation(QSGListView::Orientation orientation)
+{
+ Q_D(QSGListView);
+ if (d->orient != orientation) {
+ d->orient = orientation;
+ if (d->orient == QSGListView::Vertical) {
+ setContentWidth(-1);
+ setFlickableDirection(VerticalFlick);
+ } else {
+ setContentHeight(-1);
+ setFlickableDirection(HorizontalFlick);
+ }
+ d->regenerate();
+ emit orientationChanged();
+ }
+}
+
+Qt::LayoutDirection QSGListView::layoutDirection() const
+{
+ Q_D(const QSGListView);
+ return d->layoutDirection;
+}
+
+void QSGListView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QSGListView);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ d->regenerate();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+Qt::LayoutDirection QSGListView::effectiveLayoutDirection() const
+{
+ Q_D(const QSGListView);
+ if (d->effectiveLayoutMirror)
+ return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return d->layoutDirection;
+}
+
+bool QSGListView::isWrapEnabled() const
+{
+ Q_D(const QSGListView);
+ return d->wrap;
+}
+
+void QSGListView::setWrapEnabled(bool wrap)
+{
+ Q_D(QSGListView);
+ if (d->wrap == wrap)
+ return;
+ d->wrap = wrap;
+ emit keyNavigationWrapsChanged();
+}
+
+int QSGListView::cacheBuffer() const
+{
+ Q_D(const QSGListView);
+ return d->buffer;
+}
+
+void QSGListView::setCacheBuffer(int b)
+{
+ Q_D(QSGListView);
+ if (d->buffer != b) {
+ d->buffer = b;
+ if (isComponentComplete()) {
+ d->bufferMode = QSGListViewPrivate::BufferBefore | QSGListViewPrivate::BufferAfter;
+ refill();
+ }
+ emit cacheBufferChanged();
+ }
+}
+
+QSGViewSection *QSGListView::sectionCriteria()
+{
+ Q_D(QSGListView);
+ if (!d->sectionCriteria) {
+ d->sectionCriteria = new QSGViewSection(this);
+ connect(d->sectionCriteria, SIGNAL(propertyChanged()), this, SLOT(updateSections()));
+ }
+ return d->sectionCriteria;
+}
+
+QString QSGListView::currentSection() const
+{
+ Q_D(const QSGListView);
+ return d->currentSection;
+}
+
+qreal QSGListView::highlightMoveSpeed() const
+{
+ Q_D(const QSGListView);\
+ return d->highlightMoveSpeed;
+}
+
+void QSGListView::setHighlightMoveSpeed(qreal speed)
+{
+ Q_D(QSGListView);\
+ if (d->highlightMoveSpeed != speed) {
+ d->highlightMoveSpeed = speed;
+ if (d->highlightPosAnimator)
+ d->highlightPosAnimator->velocity = d->highlightMoveSpeed;
+ emit highlightMoveSpeedChanged();
+ }
+}
+
+int QSGListView::highlightMoveDuration() const
+{
+ Q_D(const QSGListView);
+ return d->highlightMoveDuration;
+}
+
+void QSGListView::setHighlightMoveDuration(int duration)
+{
+ Q_D(QSGListView);\
+ if (d->highlightMoveDuration != duration) {
+ d->highlightMoveDuration = duration;
+ if (d->highlightPosAnimator)
+ d->highlightPosAnimator->userDuration = d->highlightMoveDuration;
+ emit highlightMoveDurationChanged();
+ }
+}
+
+qreal QSGListView::highlightResizeSpeed() const
+{
+ Q_D(const QSGListView);\
+ return d->highlightResizeSpeed;
+}
+
+void QSGListView::setHighlightResizeSpeed(qreal speed)
+{
+ Q_D(QSGListView);\
+ if (d->highlightResizeSpeed != speed) {
+ d->highlightResizeSpeed = speed;
+ if (d->highlightSizeAnimator)
+ d->highlightSizeAnimator->velocity = d->highlightResizeSpeed;
+ emit highlightResizeSpeedChanged();
+ }
+}
+
+int QSGListView::highlightResizeDuration() const
+{
+ Q_D(const QSGListView);
+ return d->highlightResizeDuration;
+}
+
+void QSGListView::setHighlightResizeDuration(int duration)
+{
+ Q_D(QSGListView);\
+ if (d->highlightResizeDuration != duration) {
+ d->highlightResizeDuration = duration;
+ if (d->highlightSizeAnimator)
+ d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
+ emit highlightResizeDurationChanged();
+ }
+}
+
+QSGListView::SnapMode QSGListView::snapMode() const
+{
+ Q_D(const QSGListView);
+ return d->snapMode;
+}
+
+void QSGListView::setSnapMode(SnapMode mode)
+{
+ Q_D(QSGListView);
+ if (d->snapMode != mode) {
+ d->snapMode = mode;
+ emit snapModeChanged();
+ }
+}
+
+QDeclarativeComponent *QSGListView::footer() const
+{
+ Q_D(const QSGListView);
+ return d->footerComponent;
+}
+
+void QSGListView::setFooter(QDeclarativeComponent *footer)
+{
+ Q_D(QSGListView);
+ if (d->footerComponent != footer) {
+ if (d->footer) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ d->footer->item->setParentItem(0);
+ d->footer->item->deleteLater();
+ delete d->footer;
+ d->footer = 0;
+ }
+ d->footerComponent = footer;
+ d->minExtentDirty = true;
+ d->maxExtentDirty = true;
+ if (isComponentComplete()) {
+ d->updateFooter();
+ d->updateViewport();
+ d->fixupPosition();
+ }
+ emit footerChanged();
+ }
+}
+
+QDeclarativeComponent *QSGListView::header() const
+{
+ Q_D(const QSGListView);
+ return d->headerComponent;
+}
+
+void QSGListView::setHeader(QDeclarativeComponent *header)
+{
+ Q_D(QSGListView);
+ if (d->headerComponent != header) {
+ if (d->header) {
+ // XXX todo - the original did scene()->removeItem(). Why?
+ d->header->item->setParentItem(0);
+ d->header->item->deleteLater();
+ delete d->header;
+ d->header = 0;
+ }
+ d->headerComponent = header;
+ d->minExtentDirty = true;
+ d->maxExtentDirty = true;
+ if (isComponentComplete()) {
+ d->updateHeader();
+ d->updateFooter();
+ d->updateViewport();
+ d->fixupPosition();
+ }
+ emit headerChanged();
+ }
+}
+
+void QSGListView::setContentX(qreal pos)
+{
+ Q_D(QSGListView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QSGListViewPrivate::Other;
+ QSGFlickable::setContentX(pos);
+}
+
+void QSGListView::setContentY(qreal pos)
+{
+ Q_D(QSGListView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QSGListViewPrivate::Other;
+ QSGFlickable::setContentY(pos);
+}
+
+void QSGListView::updatePolish()
+{
+ Q_D(QSGListView);
+ QSGFlickable::updatePolish();
+ d->layout();
+}
+
+void QSGListView::viewportMoved()
+{
+ Q_D(QSGListView);
+ QSGFlickable::viewportMoved();
+ if (!d->itemCount)
+ return;
+ // Recursion can occur due to refill changing the content size.
+ if (d->inViewportMoved)
+ return;
+ d->inViewportMoved = true;
+ d->lazyRelease = true;
+ refill();
+ if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
+ d->moveReason = QSGListViewPrivate::Mouse;
+ if (d->moveReason != QSGListViewPrivate::SetIndex) {
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
+ // reposition highlight
+ qreal pos = d->highlight->position();
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeft()) {
+ // Handle Right-To-Left exceptions
+ viewPos = -d->position()-d->size();
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ } else {
+ viewPos = d->position();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ }
+ if (pos > viewPos + highlightEnd - d->highlight->size())
+ pos = viewPos + highlightEnd - d->highlight->size();
+ if (pos < viewPos + highlightStart)
+ pos = viewPos + highlightStart;
+ d->highlightPosAnimator->stop();
+ d->highlight->setPosition(qRound(pos));
+
+ // update current index
+ if (FxListItemSG *snapItem = d->snapItemAt(d->highlight->position())) {
+ if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
+ d->updateCurrent(snapItem->index);
+ }
+ }
+ }
+
+ if ((d->flickingHorizontally || d->flickingVertically) && d->correctFlick && !d->inFlickCorrection) {
+ d->inFlickCorrection = true;
+ // Near an end and it seems that the extent has changed?
+ // Recalculate the flick so that we don't end up in an odd position.
+ if (yflick()) {
+ if (d->vData.velocity > 0) {
+ const qreal minY = minYExtent();
+ if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
+ && minY != d->vData.flickTarget)
+ d->flickY(-d->vData.smoothVelocity.value());
+ d->bufferMode = QSGListViewPrivate::BufferBefore;
+ } else if (d->vData.velocity < 0) {
+ const qreal maxY = maxYExtent();
+ if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
+ && maxY != d->vData.flickTarget)
+ d->flickY(-d->vData.smoothVelocity.value());
+ d->bufferMode = QSGListViewPrivate::BufferAfter;
+ }
+ }
+
+ if (xflick()) {
+ if (d->hData.velocity > 0) {
+ const qreal minX = minXExtent();
+ if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
+ && minX != d->hData.flickTarget)
+ d->flickX(-d->hData.smoothVelocity.value());
+ d->bufferMode = d->isRightToLeft() ? QSGListViewPrivate::BufferAfter : QSGListViewPrivate::BufferBefore;
+ } else if (d->hData.velocity < 0) {
+ const qreal maxX = maxXExtent();
+ if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
+ && maxX != d->hData.flickTarget)
+ d->flickX(-d->hData.smoothVelocity.value());
+ d->bufferMode = d->isRightToLeft() ? QSGListViewPrivate::BufferBefore : QSGListViewPrivate::BufferAfter;
+ }
+ }
+ d->inFlickCorrection = false;
+ }
+ d->inViewportMoved = false;
+}
+
+qreal QSGListView::minYExtent() const
+{
+ Q_D(const QSGListView);
+ if (d->orient == QSGListView::Horizontal)
+ return QSGFlickable::minYExtent();
+ if (d->minExtentDirty) {
+ d->minExtent = -d->startPosition();
+ if (d->header && d->visibleItems.count())
+ d->minExtent += d->header->size();
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ d->minExtent += d->highlightRangeStart;
+ if (d->sectionCriteria) {
+ if (d->visibleItem(0))
+ d->minExtent -= d->visibleItem(0)->sectionSize();
+ }
+ d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd + 1));
+ }
+ d->minExtentDirty = false;
+ }
+
+ return d->minExtent;
+}
+
+qreal QSGListView::maxYExtent() const
+{
+ Q_D(const QSGListView);
+ if (d->orient == QSGListView::Horizontal)
+ return height();
+ if (d->maxExtentDirty) {
+ if (!d->model || !d->model->count()) {
+ d->maxExtent = d->header ? -d->header->size() : 0;
+ d->maxExtent += height();
+ } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart);
+ if (d->highlightRangeEnd != d->highlightRangeStart)
+ d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd + 1));
+ } else {
+ d->maxExtent = -(d->endPosition() - height() + 1);
+ }
+ if (d->footer)
+ d->maxExtent -= d->footer->size();
+ qreal minY = minYExtent();
+ if (d->maxExtent > minY)
+ d->maxExtent = minY;
+ d->maxExtentDirty = false;
+ }
+ return d->maxExtent;
+}
+
+qreal QSGListView::minXExtent() const
+{
+ Q_D(const QSGListView);
+ if (d->orient == QSGListView::Vertical)
+ return QSGFlickable::minXExtent();
+ if (d->minExtentDirty) {
+ d->minExtent = -d->startPosition();
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal endPositionFirstItem = 0;
+ if (d->isRightToLeft()) {
+ if (d->model && d->model->count())
+ endPositionFirstItem = d->positionAt(d->model->count()-1);
+ else if (d->header)
+ d->minExtent += d->header->size();
+ highlightStart = d->highlightRangeStartValid
+ ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
+ : d->size() - (d->lastPosition()-endPositionFirstItem);
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
+ if (d->footer)
+ d->minExtent += d->footer->size();
+ qreal maxX = maxXExtent();
+ if (d->minExtent < maxX)
+ d->minExtent = maxX;
+ } else {
+ endPositionFirstItem = d->endPositionAt(0);
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->header && d->visibleItems.count())
+ d->minExtent += d->header->size();
+ }
+ if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ d->minExtent += highlightStart;
+ d->minExtent = qMax(d->minExtent, -(endPositionFirstItem - highlightEnd + 1));
+ }
+ d->minExtentDirty = false;
+ }
+
+ return d->minExtent;
+}
+
+qreal QSGListView::maxXExtent() const
+{
+ Q_D(const QSGListView);
+ if (d->orient == QSGListView::Vertical)
+ return width();
+ if (d->maxExtentDirty) {
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal lastItemPosition = 0;
+ d->maxExtent = 0;
+ if (d->isRightToLeft()) {
+ highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
+ lastItemPosition = d->endPosition();
+ } else {
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->model && d->model->count())
+ lastItemPosition = d->positionAt(d->model->count()-1);
+ }
+ if (!d->model || !d->model->count()) {
+ if (!d->isRightToLeft())
+ d->maxExtent = d->header ? -d->header->size() : 0;
+ d->maxExtent += width();
+ } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ d->maxExtent = -(lastItemPosition - highlightStart);
+ if (highlightEnd != highlightStart) {
+ d->maxExtent = d->isRightToLeft()
+ ? qMax(d->maxExtent, -(d->endPosition() - highlightEnd + 1))
+ : qMin(d->maxExtent, -(d->endPosition() - highlightEnd + 1));
+ }
+ } else {
+ d->maxExtent = -(d->endPosition() - width() + 1);
+ }
+ if (d->isRightToLeft()) {
+ if (d->header && d->visibleItems.count())
+ d->maxExtent -= d->header->size();
+ } else {
+ if (d->footer)
+ d->maxExtent -= d->footer->size();
+ qreal minX = minXExtent();
+ if (d->maxExtent > minX)
+ d->maxExtent = minX;
+ }
+ d->maxExtentDirty = false;
+ }
+
+ return d->maxExtent;
+}
+
+void QSGListView::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QSGListView);
+ if (d->model && d->model->count() && d->interactive) {
+ if ((!d->isRightToLeft() && event->key() == Qt::Key_Left)
+ || (d->orient == QSGListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
+ || (d->orient == QSGListView::Vertical && event->key() == Qt::Key_Up)) {
+ if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) {
+ decrementCurrentIndex();
+ event->accept();
+ return;
+ } else if (d->wrap) {
+ event->accept();
+ return;
+ }
+ } else if ((!d->isRightToLeft() && event->key() == Qt::Key_Right)
+ || (d->orient == QSGListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
+ || (d->orient == QSGListView::Vertical && event->key() == Qt::Key_Down)) {
+ if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) {
+ incrementCurrentIndex();
+ event->accept();
+ return;
+ } else if (d->wrap) {
+ event->accept();
+ return;
+ }
+ }
+ }
+ event->ignore();
+ QSGFlickable::keyPressEvent(event);
+}
+
+void QSGListView::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QSGListView);
+ d->maxExtentDirty = true;
+ d->minExtentDirty = true;
+ if (d->isRightToLeft() && d->orient == QSGListView::Horizontal) {
+ // maintain position relative to the right edge
+ int dx = newGeometry.width() - oldGeometry.width();
+ setContentX(contentX() - dx);
+ }
+ QSGFlickable::geometryChanged(newGeometry, oldGeometry);
+}
+
+
+void QSGListView::incrementCurrentIndex()
+{
+ Q_D(QSGListView);
+ int count = d->model ? d->model->count() : 0;
+ if (count && (currentIndex() < count - 1 || d->wrap)) {
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ int index = currentIndex()+1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+}
+
+void QSGListView::decrementCurrentIndex()
+{
+ Q_D(QSGListView);
+ int count = d->model ? d->model->count() : 0;
+ if (count && (currentIndex() > 0 || d->wrap)) {
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ int index = currentIndex()-1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+}
+
+void QSGListViewPrivate::positionViewAtIndex(int index, int mode)
+{
+ Q_Q(QSGListView);
+ if (!isValid())
+ return;
+ if (mode < QSGListView::Beginning || mode > QSGListView::Contain)
+ return;
+ int idx = qMax(qMin(index, model->count()-1), 0);
+
+ if (layoutScheduled)
+ layout();
+ qreal pos = isRightToLeft() ? -position() - size() : position();
+ FxListItemSG *item = visibleItem(idx);
+ qreal maxExtent;
+ if (orient == QSGListView::Vertical)
+ maxExtent = -q->maxYExtent();
+ else
+ maxExtent = isRightToLeft() ? q->minXExtent()-size(): -q->maxXExtent();
+ if (!item) {
+ int itemPos = positionAt(idx);
+ // save the currently visible items in case any of them end up visible again
+ QList<FxListItemSG*> oldVisible = visibleItems;
+ visibleItems.clear();
+ visiblePos = itemPos;
+ visibleIndex = idx;
+ setPosition(qMin(qreal(itemPos), maxExtent));
+ // now release the reference to all the old visible items.
+ for (int i = 0; i < oldVisible.count(); ++i)
+ releaseItem(oldVisible.at(i));
+ item = visibleItem(idx);
+ }
+ if (item) {
+ const qreal itemPos = item->position();
+ switch (mode) {
+ case QSGListView::Beginning:
+ pos = itemPos;
+ if (index < 0 && header)
+ pos -= header->size();
+ break;
+ case QSGListView::Center:
+ pos = itemPos - (size() - item->size())/2;
+ break;
+ case QSGListView::End:
+ pos = itemPos - size() + item->size();
+ if (index >= model->count() && footer)
+ pos += footer->size();
+ break;
+ case QSGListView::Visible:
+ if (itemPos > pos + size())
+ pos = itemPos - size() + item->size();
+ else if (item->endPosition() < pos)
+ pos = itemPos;
+ break;
+ case QSGListView::Contain:
+ if (item->endPosition() > pos + size())
+ pos = itemPos - size() + item->size();
+ if (itemPos < pos)
+ pos = itemPos;
+ }
+ pos = qMin(pos, maxExtent);
+ qreal minExtent;
+ if (orient == QSGListView::Vertical) {
+ minExtent = -q->minYExtent();
+ } else {
+ minExtent = isRightToLeft() ? q->maxXExtent()-size(): -q->minXExtent();
+ }
+ pos = qMax(pos, minExtent);
+ moveReason = QSGListViewPrivate::Other;
+ q->cancelFlick();
+ setPosition(pos);
+ if (highlight) {
+ if (autoHighlight) {
+ highlight->setPosition(currentItem->itemPosition());
+ highlight->setSize(currentItem->itemSize());
+ }
+ updateHighlight();
+ }
+ }
+ fixupPosition();
+}
+
+void QSGListView::positionViewAtIndex(int index, int mode)
+{
+ Q_D(QSGListView);
+ if (!d->isValid() || index < 0 || index >= d->model->count())
+ return;
+ d->positionViewAtIndex(index, mode);
+}
+
+void QSGListView::positionViewAtBeginning()
+{
+ Q_D(QSGListView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(-1, Beginning);
+}
+
+void QSGListView::positionViewAtEnd()
+{
+ Q_D(QSGListView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(d->model->count(), End);
+}
+
+int QSGListView::indexAt(qreal x, qreal y) const
+{
+ Q_D(const QSGListView);
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ const FxListItemSG *listItem = d->visibleItems.at(i);
+ if(listItem->contains(x, y))
+ return listItem->index;
+ }
+
+ return -1;
+}
+
+void QSGListView::componentComplete()
+{
+ Q_D(QSGListView);
+ QSGFlickable::componentComplete();
+ updateSections();
+ d->updateHeader();
+ d->updateFooter();
+ if (d->isValid()) {
+ refill();
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ if (d->currentIndex < 0 && !d->currentIndexCleared)
+ d->updateCurrent(0);
+ else
+ d->updateCurrent(d->currentIndex);
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->position());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGListViewPrivate::Other;
+ d->fixupPosition();
+ }
+}
+
+void QSGListView::updateSections()
+{
+ Q_D(QSGListView);
+ if (isComponentComplete() && d->model) {
+ QList<QByteArray> roles;
+ if (d->sectionCriteria && !d->sectionCriteria->property().isEmpty())
+ roles << d->sectionCriteria->property().toUtf8();
+ d->model->setWatchedRoles(roles);
+ d->updateSections();
+ if (d->itemCount)
+ d->layout();
+ }
+}
+
+void QSGListView::refill()
+{
+ Q_D(QSGListView);
+ if (d->isRightToLeft())
+ d->refill(-d->position()-d->size()+1, -d->position());
+ else
+ d->refill(d->position(), d->position()+d->size()-1);
+}
+
+void QSGListView::trackedPositionChanged()
+{
+ Q_D(QSGListView);
+ if (!d->trackedItem || !d->currentItem)
+ return;
+ if (d->moveReason == QSGListViewPrivate::SetIndex) {
+ qreal trackedPos = qCeil(d->trackedItem->position());
+ qreal trackedSize = d->trackedItem->size();
+ if (d->trackedItem != d->currentItem) {
+ trackedPos -= d->currentItem->sectionSize();
+ trackedSize += d->currentItem->sectionSize();
+ }
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeft()) {
+ viewPos = -d->position()-d->size();
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ } else {
+ viewPos = d->position();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ }
+ qreal pos = viewPos;
+ if (d->haveHighlightRange) {
+ if (d->highlightRange == StrictlyEnforceRange) {
+ if (trackedPos > pos + highlightEnd - d->trackedItem->size())
+ pos = trackedPos - highlightEnd + d->trackedItem->size();
+ if (trackedPos < pos + highlightStart)
+ pos = trackedPos - highlightStart;
+ } else {
+ if (trackedPos < d->startPosition() + highlightStart) {
+ pos = d->startPosition();
+ } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + highlightEnd) {
+ pos = d->endPosition() - d->size() + 1;
+ if (pos < d->startPosition())
+ pos = d->startPosition();
+ } else {
+ if (trackedPos < viewPos + highlightStart) {
+ pos = trackedPos - highlightStart;
+ } else if (trackedPos > viewPos + highlightEnd - trackedSize) {
+ pos = trackedPos - highlightEnd + trackedSize;
+ }
+ }
+ }
+ } else {
+ if (trackedPos < viewPos && d->currentItem->position() < viewPos) {
+ pos = d->currentItem->position() < trackedPos ? trackedPos : d->currentItem->position();
+ } else if (d->trackedItem->endPosition() >= viewPos + d->size()
+ && d->currentItem->endPosition() >= viewPos + d->size()) {
+ if (d->trackedItem->endPosition() <= d->currentItem->endPosition()) {
+ pos = d->trackedItem->endPosition() - d->size() + 1;
+ if (trackedSize > d->size())
+ pos = trackedPos;
+ } else {
+ pos = d->currentItem->endPosition() - d->size() + 1;
+ if (d->currentItem->size() > d->size())
+ pos = d->currentItem->position();
+ }
+ }
+ }
+ if (viewPos != pos) {
+ cancelFlick();
+ d->calcVelocity = true;
+ d->setPosition(pos);
+ d->calcVelocity = false;
+ }
+ }
+}
+
+void QSGListView::itemsInserted(int modelIndex, int count)
+{
+ Q_D(QSGListView);
+ if (!isComponentComplete())
+ return;
+ d->updateUnrequestedIndexes();
+ d->moveReason = QSGListViewPrivate::Other;
+
+ qreal tempPos = d->isRightToLeft() ? -d->position()-d->size() : d->position();
+ int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
+ if (index < 0) {
+ int i = d->visibleItems.count() - 1;
+ while (i > 0 && d->visibleItems.at(i)->index == -1)
+ --i;
+ if (i == 0 && d->visibleItems.first()->index == -1) {
+ // there are no visible items except items marked for removal
+ index = d->visibleItems.count();
+ } else if (d->visibleItems.at(i)->index + 1 == modelIndex
+ && d->visibleItems.at(i)->endPosition() < d->buffer+tempPos+d->size()-1) {
+ // Special case of appending an item to the model.
+ index = d->visibleItems.count();
+ } else {
+ if (modelIndex < d->visibleIndex) {
+ // Insert before visible items
+ d->visibleIndex += count;
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxListItemSG *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem->index >= modelIndex)
+ listItem->index += count;
+ }
+ }
+ if (d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem)
+ d->currentItem->index = d->currentIndex;
+ emit currentIndexChanged();
+ }
+ d->scheduleLayout();
+ d->itemCount += count;
+ emit countChanged();
+ return;
+ }
+ }
+
+ // index can be the next item past the end of the visible items list (i.e. appended)
+ int pos = 0;
+ if (d->visibleItems.count()) {
+ pos = index < d->visibleItems.count() ? d->visibleItems.at(index)->position()
+ : d->visibleItems.last()->endPosition()+d->spacing+1;
+ } else if (d->itemCount == 0 && d->header) {
+ pos = d->header->size();
+ }
+
+ int initialPos = pos;
+ int diff = 0;
+ QList<FxListItemSG*> added;
+ bool addedVisible = false;
+ FxListItemSG *firstVisible = d->firstVisibleItem();
+ if (firstVisible && pos < firstVisible->position()) {
+ // Insert items before the visible item.
+ int insertionIdx = index;
+ int i = 0;
+ int from = tempPos - d->buffer;
+ for (i = count-1; i >= 0 && pos > from; --i) {
+ if (!addedVisible) {
+ d->scheduleLayout();
+ addedVisible = true;
+ }
+ FxListItemSG *item = d->createItem(modelIndex + i);
+ d->visibleItems.insert(insertionIdx, item);
+ pos -= item->size() + d->spacing;
+ item->setPosition(pos);
+ index++;
+ }
+ if (i >= 0) {
+ // If we didn't insert all our new items - anything
+ // before the current index is not visible - remove it.
+ while (insertionIdx--) {
+ FxListItemSG *item = d->visibleItems.takeFirst();
+ if (item->index != -1)
+ d->visibleIndex++;
+ d->releaseItem(item);
+ }
+ } else {
+ // adjust pos of items before inserted items.
+ for (int i = insertionIdx-1; i >= 0; i--) {
+ FxListItemSG *listItem = d->visibleItems.at(i);
+ listItem->setPosition(listItem->position() - (initialPos - pos));
+ }
+ }
+ } else {
+ int i = 0;
+ int to = d->buffer+tempPos+d->size()-1;
+ for (i = 0; i < count && pos <= to; ++i) {
+ if (!addedVisible) {
+ d->scheduleLayout();
+ addedVisible = true;
+ }
+ FxListItemSG *item = d->createItem(modelIndex + i);
+ d->visibleItems.insert(index, item);
+ item->setPosition(pos);
+ added.append(item);
+ pos += item->size() + d->spacing;
+ ++index;
+ }
+ if (i != count) {
+ // We didn't insert all our new items, which means anything
+ // beyond the current index is not visible - remove it.
+ while (d->visibleItems.count() > index)
+ d->releaseItem(d->visibleItems.takeLast());
+ }
+ diff = pos - initialPos;
+ }
+ if (d->itemCount && d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem) {
+ d->currentItem->index = d->currentIndex;
+ d->currentItem->setPosition(d->currentItem->position() + diff);
+ }
+ emit currentIndexChanged();
+ } else if (!d->itemCount && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
+ d->updateCurrent(0);
+ }
+ // Update the indexes of the following visible items.
+ for (; index < d->visibleItems.count(); ++index) {
+ FxListItemSG *listItem = d->visibleItems.at(index);
+ if (d->currentItem && listItem->item != d->currentItem->item)
+ listItem->setPosition(listItem->position() + diff);
+ if (listItem->index != -1)
+ listItem->index += count;
+ }
+ // everything is in order now - emit add() signal
+ for (int j = 0; j < added.count(); ++j)
+ added.at(j)->attached->emitAdd();
+
+ d->updateSections();
+ d->itemCount += count;
+ emit countChanged();
+}
+
+void QSGListView::itemsRemoved(int modelIndex, int count)
+{
+ Q_D(QSGListView);
+ if (!isComponentComplete())
+ return;
+ d->moveReason = QSGListViewPrivate::Other;
+ d->updateUnrequestedIndexes();
+ d->itemCount -= count;
+
+ FxListItemSG *firstVisible = d->firstVisibleItem();
+ int preRemovedSize = 0;
+ bool removedVisible = false;
+ // Remove the items from the visible list, skipping anything already marked for removal
+ QList<FxListItemSG*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxListItemSG *item = *it;
+ if (item->index == -1 || item->index < modelIndex) {
+ // already removed, or before removed items
+ ++it;
+ } else if (item->index >= modelIndex + count) {
+ // after removed items
+ item->index -= count;
+ ++it;
+ } else {
+ // removed item
+ if (!removedVisible) {
+ d->scheduleLayout();
+ removedVisible = true;
+ }
+ item->attached->emitRemove();
+ if (item->attached->delayRemove()) {
+ item->index = -1;
+ connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
+ ++it;
+ } else {
+ if (item == firstVisible)
+ firstVisible = 0;
+ if (firstVisible && item->position() < firstVisible->position())
+ preRemovedSize += item->size();
+ it = d->visibleItems.erase(it);
+ d->releaseItem(item);
+ }
+ }
+ }
+
+ if (firstVisible && d->visibleItems.first() != firstVisible)
+ d->visibleItems.first()->setPosition(d->visibleItems.first()->position() + preRemovedSize);
+
+ // fix current
+ if (d->currentIndex >= modelIndex + count) {
+ d->currentIndex -= count;
+ if (d->currentItem)
+ d->currentItem->index -= count;
+ emit currentIndexChanged();
+ } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
+ // current item has been removed.
+ if (d->currentItem) {
+ d->currentItem->attached->setIsCurrentItem(false);
+ d->releaseItem(d->currentItem);
+ d->currentItem = 0;
+ }
+ d->currentIndex = -1;
+ if (d->itemCount)
+ d->updateCurrent(qMin(modelIndex, d->itemCount-1));
+ else
+ emit currentIndexChanged();
+ }
+
+ // update visibleIndex
+ bool haveVisibleIndex = false;
+ for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ haveVisibleIndex = true;
+ break;
+ }
+ }
+
+ if (removedVisible && !haveVisibleIndex) {
+ d->timeline.clear();
+ if (d->itemCount == 0) {
+ d->visibleIndex = 0;
+ d->visiblePos = d->header ? d->header->size() : 0;
+ d->setPosition(0);
+ d->updateHeader();
+ d->updateFooter();
+ } else {
+ if (modelIndex < d->visibleIndex)
+ d->visibleIndex = modelIndex+1;
+ d->visibleIndex = qMax(qMin(d->visibleIndex, d->itemCount-1), 0);
+ }
+ }
+
+ d->updateSections();
+ emit countChanged();
+}
+
+void QSGListView::destroyRemoved()
+{
+ Q_D(QSGListView);
+ for (QList<FxListItemSG*>::Iterator it = d->visibleItems.begin();
+ it != d->visibleItems.end();) {
+ FxListItemSG *listItem = *it;
+ if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
+ d->releaseItem(listItem);
+ it = d->visibleItems.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Correct the positioning of the items
+ d->updateSections();
+ d->layout();
+}
+
+void QSGListView::itemsMoved(int from, int to, int count)
+{
+ Q_D(QSGListView);
+ if (!isComponentComplete())
+ return;
+ d->updateUnrequestedIndexes();
+
+ if (d->visibleItems.isEmpty()) {
+ refill();
+ return;
+ }
+
+ d->moveReason = QSGListViewPrivate::Other;
+ FxListItemSG *firstVisible = d->firstVisibleItem();
+ qreal firstItemPos = firstVisible->position();
+ QHash<int,FxListItemSG*> moved;
+ int moveBy = 0;
+
+ QList<FxListItemSG*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxListItemSG *item = *it;
+ if (item->index >= from && item->index < from + count) {
+ // take the items that are moving
+ item->index += (to-from);
+ moved.insert(item->index, item);
+ if (item->position() < firstItemPos)
+ moveBy += item->size();
+ it = d->visibleItems.erase(it);
+ } else {
+ // move everything after the moved items.
+ if (item->index > from && item->index != -1)
+ item->index -= count;
+ ++it;
+ }
+ }
+
+ int remaining = count;
+ int endIndex = d->visibleIndex;
+ it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxListItemSG *item = *it;
+ if (remaining && item->index >= to && item->index < to + count) {
+ // place items in the target position, reusing any existing items
+ FxListItemSG *movedItem = moved.take(item->index);
+ if (!movedItem)
+ movedItem = d->createItem(item->index);
+ if (item->index <= firstVisible->index)
+ moveBy -= movedItem->size();
+ it = d->visibleItems.insert(it, movedItem);
+ ++it;
+ --remaining;
+ } else {
+ if (item->index != -1) {
+ if (item->index >= to) {
+ // update everything after the moved items.
+ item->index += count;
+ }
+ endIndex = item->index;
+ }
+ ++it;
+ }
+ }
+
+ // If we have moved items to the end of the visible items
+ // then add any existing moved items that we have
+ while (FxListItemSG *item = moved.take(endIndex+1)) {
+ d->visibleItems.append(item);
+ ++endIndex;
+ }
+
+ // update visibleIndex
+ for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ break;
+ }
+ }
+
+ // Fix current index
+ if (d->currentIndex >= 0 && d->currentItem) {
+ int oldCurrent = d->currentIndex;
+ d->currentIndex = d->model->indexOf(d->currentItem->item, this);
+ if (oldCurrent != d->currentIndex) {
+ d->currentItem->index = d->currentIndex;
+ emit currentIndexChanged();
+ }
+ }
+
+ // Whatever moved items remain are no longer visible items.
+ while (moved.count()) {
+ int idx = moved.begin().key();
+ FxListItemSG *item = moved.take(idx);
+ if (d->currentItem && item->item == d->currentItem->item)
+ item->setPosition(d->positionAt(idx));
+ d->releaseItem(item);
+ }
+
+ // Ensure we don't cause an ugly list scroll.
+ d->visibleItems.first()->setPosition(d->visibleItems.first()->position() + moveBy);
+
+ d->updateSections();
+ d->layout();
+}
+
+void QSGListView::itemsChanged(int, int)
+{
+ Q_D(QSGListView);
+ d->updateSections();
+ d->layout();
+}
+
+void QSGListView::modelReset()
+{
+ Q_D(QSGListView);
+ d->moveReason = QSGListViewPrivate::SetIndex;
+ d->regenerate();
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->position());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QSGListViewPrivate::Other;
+ emit countChanged();
+}
+
+void QSGListView::createdItem(int index, QSGItem *item)
+{
+ Q_D(QSGListView);
+ if (d->requestedIndex != index) {
+ item->setParentItem(contentItem());
+ d->unrequestedItems.insert(item, index);
+ if (d->orient == QSGListView::Vertical) {
+ item->setY(d->positionAt(index));
+ } else {
+ if (d->isRightToLeft())
+ item->setX(-d->positionAt(index)-item->width());
+ else
+ item->setX(d->positionAt(index));
+ }
+ }
+}
+
+void QSGListView::destroyingItem(QSGItem *item)
+{
+ Q_D(QSGListView);
+ d->unrequestedItems.remove(item);
+}
+
+void QSGListView::animStopped()
+{
+ Q_D(QSGListView);
+ d->bufferMode = QSGListViewPrivate::NoBuffer;
+ if (d->haveHighlightRange && d->highlightRange == QSGListView::StrictlyEnforceRange)
+ d->updateHighlight();
+}
+
+QSGListViewAttached *QSGListView::qmlAttachedProperties(QObject *obj)
+{
+ return new QSGListViewAttached(obj);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsglistview_p.h b/src/declarative/items/qsglistview_p.h
new file mode 100644
index 0000000000..2e3df2020f
--- /dev/null
+++ b/src/declarative/items/qsglistview_p.h
@@ -0,0 +1,374 @@
+// Commit: 95814418f9d6adeba365c795462e8afb00138211
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGLISTVIEW_P_H
+#define QSGLISTVIEW_P_H
+
+#include "qsgflickable_p.h"
+
+#include <private/qdeclarativeguard_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QSGViewSection : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged)
+ Q_PROPERTY(SectionCriteria criteria READ criteria WRITE setCriteria NOTIFY criteriaChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_ENUMS(SectionCriteria)
+public:
+ QSGViewSection(QObject *parent=0) : QObject(parent), m_criteria(FullString), m_delegate(0) {}
+
+ QString property() const { return m_property; }
+ void setProperty(const QString &);
+
+ enum SectionCriteria { FullString, FirstCharacter };
+ SectionCriteria criteria() const { return m_criteria; }
+ void setCriteria(SectionCriteria);
+
+ QDeclarativeComponent *delegate() const { return m_delegate; }
+ void setDelegate(QDeclarativeComponent *delegate);
+
+ QString sectionString(const QString &value);
+
+Q_SIGNALS:
+ void propertyChanged();
+ void criteriaChanged();
+ void delegateChanged();
+
+private:
+ QString m_property;
+ SectionCriteria m_criteria;
+ QDeclarativeComponent *m_delegate;
+};
+
+
+class QSGVisualModel;
+class QSGListViewAttached;
+class QSGListViewPrivate;
+class Q_AUTOTEST_EXPORT QSGListView : public QSGFlickable
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGListView)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+ Q_PROPERTY(QSGItem *currentItem READ currentItem NOTIFY currentIndexChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+
+ Q_PROPERTY(QDeclarativeComponent *highlight READ highlight WRITE setHighlight NOTIFY highlightChanged)
+ Q_PROPERTY(QSGItem *highlightItem READ highlightItem NOTIFY highlightItemChanged)
+ Q_PROPERTY(bool highlightFollowsCurrentItem READ highlightFollowsCurrentItem WRITE setHighlightFollowsCurrentItem NOTIFY highlightFollowsCurrentItemChanged)
+ Q_PROPERTY(qreal highlightMoveSpeed READ highlightMoveSpeed WRITE setHighlightMoveSpeed NOTIFY highlightMoveSpeedChanged)
+ Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged)
+ Q_PROPERTY(qreal highlightResizeSpeed READ highlightResizeSpeed WRITE setHighlightResizeSpeed NOTIFY highlightResizeSpeedChanged)
+ Q_PROPERTY(int highlightResizeDuration READ highlightResizeDuration WRITE setHighlightResizeDuration NOTIFY highlightResizeDurationChanged)
+
+ Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged RESET resetPreferredHighlightBegin)
+ Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd)
+ Q_PROPERTY(HighlightRangeMode highlightRangeMode READ highlightRangeMode WRITE setHighlightRangeMode NOTIFY highlightRangeModeChanged)
+
+ Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
+ Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
+ Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged)
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
+ Q_PROPERTY(QSGViewSection *section READ sectionCriteria CONSTANT)
+ Q_PROPERTY(QString currentSection READ currentSection NOTIFY currentSectionChanged)
+
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
+
+ Q_PROPERTY(QDeclarativeComponent *header READ header WRITE setHeader NOTIFY headerChanged)
+ Q_PROPERTY(QDeclarativeComponent *footer READ footer WRITE setFooter NOTIFY footerChanged)
+
+ Q_ENUMS(HighlightRangeMode)
+ Q_ENUMS(Orientation)
+ Q_ENUMS(SnapMode)
+ Q_ENUMS(PositionMode)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ QSGListView(QSGItem *parent=0);
+ ~QSGListView();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ QSGItem *currentItem();
+ QSGItem *highlightItem();
+ int count() const;
+
+ QDeclarativeComponent *highlight() const;
+ void setHighlight(QDeclarativeComponent *highlight);
+
+ bool highlightFollowsCurrentItem() const;
+ void setHighlightFollowsCurrentItem(bool);
+
+ enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange };
+ HighlightRangeMode highlightRangeMode() const;
+ void setHighlightRangeMode(HighlightRangeMode mode);
+
+ qreal preferredHighlightBegin() const;
+ void setPreferredHighlightBegin(qreal);
+ void resetPreferredHighlightBegin();
+
+ qreal preferredHighlightEnd() const;
+ void setPreferredHighlightEnd(qreal);
+ void resetPreferredHighlightEnd();
+
+ qreal spacing() const;
+ void setSpacing(qreal spacing);
+
+ enum Orientation { Horizontal = Qt::Horizontal, Vertical = Qt::Vertical };
+ Orientation orientation() const;
+ void setOrientation(Orientation);
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection(Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+ bool isWrapEnabled() const;
+ void setWrapEnabled(bool);
+
+ int cacheBuffer() const;
+ void setCacheBuffer(int);
+
+ QSGViewSection *sectionCriteria();
+ QString currentSection() const;
+
+ qreal highlightMoveSpeed() const;
+ void setHighlightMoveSpeed(qreal);
+
+ int highlightMoveDuration() const;
+ void setHighlightMoveDuration(int);
+
+ qreal highlightResizeSpeed() const;
+ void setHighlightResizeSpeed(qreal);
+
+ int highlightResizeDuration() const;
+ void setHighlightResizeDuration(int);
+
+ enum SnapMode { NoSnap, SnapToItem, SnapOneItem };
+ SnapMode snapMode() const;
+ void setSnapMode(SnapMode mode);
+
+ QDeclarativeComponent *footer() const;
+ void setFooter(QDeclarativeComponent *);
+
+ QDeclarativeComponent *header() const;
+ void setHeader(QDeclarativeComponent *);
+
+ virtual void setContentX(qreal pos);
+ virtual void setContentY(qreal pos);
+
+ static QSGListViewAttached *qmlAttachedProperties(QObject *);
+
+ enum PositionMode { Beginning, Center, End, Visible, Contain };
+
+ Q_INVOKABLE void positionViewAtIndex(int index, int mode);
+ Q_INVOKABLE int indexAt(qreal x, qreal y) const;
+ Q_INVOKABLE void positionViewAtBeginning();
+ Q_INVOKABLE void positionViewAtEnd();
+
+public Q_SLOTS:
+ void incrementCurrentIndex();
+ void decrementCurrentIndex();
+
+Q_SIGNALS:
+ void countChanged();
+ void spacingChanged();
+ void orientationChanged();
+ void layoutDirectionChanged();
+ void effectiveLayoutDirectionChanged();
+ void currentIndexChanged();
+ void currentSectionChanged();
+ void highlightMoveSpeedChanged();
+ void highlightMoveDurationChanged();
+ void highlightResizeSpeedChanged();
+ void highlightResizeDurationChanged();
+ void highlightChanged();
+ void highlightItemChanged();
+ void modelChanged();
+ void delegateChanged();
+ void highlightFollowsCurrentItemChanged();
+ void preferredHighlightBeginChanged();
+ void preferredHighlightEndChanged();
+ void highlightRangeModeChanged();
+ void keyNavigationWrapsChanged();
+ void cacheBufferChanged();
+ void snapModeChanged();
+ void headerChanged();
+ void footerChanged();
+
+protected:
+ virtual void updatePolish();
+ virtual void viewportMoved();
+ virtual qreal minYExtent() const;
+ virtual qreal maxYExtent() const;
+ virtual qreal minXExtent() const;
+ virtual qreal maxXExtent() const;
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void geometryChanged(const QRectF &newGeometry,const QRectF &oldGeometry);
+ virtual void componentComplete();
+
+private Q_SLOTS:
+ void updateSections();
+ void refill();
+ void trackedPositionChanged();
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int from, int to, int count);
+ void itemsChanged(int index, int count);
+ void modelReset();
+ void destroyRemoved();
+ void createdItem(int index, QSGItem *item);
+ void destroyingItem(QSGItem *item);
+ void animStopped();
+};
+
+class QSGListViewAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QSGListViewAttached(QObject *parent)
+ : QObject(parent), m_view(0), m_isCurrent(false), m_delayRemove(false) {}
+ ~QSGListViewAttached() {}
+
+ Q_PROPERTY(QSGListView *view READ view NOTIFY viewChanged)
+ QSGListView *view() { return m_view; }
+ void setView(QSGListView *view) {
+ if (view != m_view) {
+ m_view = view;
+ emit viewChanged();
+ }
+ }
+
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged)
+ bool isCurrentItem() const { return m_isCurrent; }
+ void setIsCurrentItem(bool c) {
+ if (m_isCurrent != c) {
+ m_isCurrent = c;
+ emit currentItemChanged();
+ }
+ }
+
+ Q_PROPERTY(QString previousSection READ prevSection NOTIFY prevSectionChanged)
+ QString prevSection() const { return m_prevSection; }
+ void setPrevSection(const QString &sect) {
+ if (m_prevSection != sect) {
+ m_prevSection = sect;
+ emit prevSectionChanged();
+ }
+ }
+
+ Q_PROPERTY(QString nextSection READ nextSection NOTIFY nextSectionChanged)
+ QString nextSection() const { return m_nextSection; }
+ void setNextSection(const QString &sect) {
+ if (m_nextSection != sect) {
+ m_nextSection = sect;
+ emit nextSectionChanged();
+ }
+ }
+
+ Q_PROPERTY(QString section READ section NOTIFY sectionChanged)
+ QString section() const { return m_section; }
+ void setSection(const QString &sect) {
+ if (m_section != sect) {
+ m_section = sect;
+ emit sectionChanged();
+ }
+ }
+
+ Q_PROPERTY(bool delayRemove READ delayRemove WRITE setDelayRemove NOTIFY delayRemoveChanged)
+ bool delayRemove() const { return m_delayRemove; }
+ void setDelayRemove(bool delay) {
+ if (m_delayRemove != delay) {
+ m_delayRemove = delay;
+ emit delayRemoveChanged();
+ }
+ }
+
+ void emitAdd() { emit add(); }
+ void emitRemove() { emit remove(); }
+
+Q_SIGNALS:
+ void currentItemChanged();
+ void sectionChanged();
+ void prevSectionChanged();
+ void nextSectionChanged();
+ void delayRemoveChanged();
+ void add();
+ void remove();
+ void viewChanged();
+
+public:
+ QDeclarativeGuard<QSGListView> m_view;
+ mutable QString m_section;
+ QString m_prevSection;
+ QString m_nextSection;
+ bool m_isCurrent : 1;
+ bool m_delayRemove : 1;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(QSGListView, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QSGListView)
+QML_DECLARE_TYPE(QSGViewSection)
+
+QT_END_HEADER
+
+#endif // QSGLISTVIEW_P_H
diff --git a/src/declarative/items/qsgloader.cpp b/src/declarative/items/qsgloader.cpp
new file mode 100644
index 0000000000..6717098506
--- /dev/null
+++ b/src/declarative/items/qsgloader.cpp
@@ -0,0 +1,340 @@
+// Commit: 501180c6fbed0857126da2bb0ff1f17ee35472c6
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgloader_p_p.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGLoaderPrivate::QSGLoaderPrivate()
+ : item(0), component(0), ownComponent(false), updatingSize(false),
+ itemWidthValid(false), itemHeightValid(false)
+{
+}
+
+QSGLoaderPrivate::~QSGLoaderPrivate()
+{
+}
+
+void QSGLoaderPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (resizeItem == item) {
+ if (!updatingSize && newGeometry.width() != oldGeometry.width())
+ itemWidthValid = true;
+ if (!updatingSize && newGeometry.height() != oldGeometry.height())
+ itemHeightValid = true;
+ _q_updateSize(false);
+ }
+ QSGItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
+}
+
+void QSGLoaderPrivate::clear()
+{
+ if (ownComponent) {
+ component->deleteLater();
+ component = 0;
+ ownComponent = false;
+ }
+ source = QUrl();
+
+ if (item) {
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+ p->removeItemChangeListener(this, QSGItemPrivate::Geometry);
+
+ // We can't delete immediately because our item may have triggered
+ // the Loader to load a different item.
+ item->setParentItem(0);
+ item->setVisible(false);
+ item->deleteLater();
+ item = 0;
+ }
+}
+
+void QSGLoaderPrivate::initResize()
+{
+ QSGItemPrivate *p = QSGItemPrivate::get(item);
+ p->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ // We may override the item's size, so we need to remember
+ // whether the item provided its own valid size.
+ itemWidthValid = p->widthValid;
+ itemHeightValid = p->heightValid;
+ _q_updateSize();
+}
+
+QSGLoader::QSGLoader(QSGItem *parent)
+ : QSGImplicitSizeItem(*(new QSGLoaderPrivate), parent)
+{
+ setFlag(ItemIsFocusScope);
+}
+
+QSGLoader::~QSGLoader()
+{
+ Q_D(QSGLoader);
+ if (d->item) {
+ QSGItemPrivate *p = QSGItemPrivate::get(d->item);
+ p->removeItemChangeListener(d, QSGItemPrivate::Geometry);
+ }
+}
+
+QUrl QSGLoader::source() const
+{
+ Q_D(const QSGLoader);
+ return d->source;
+}
+
+void QSGLoader::setSource(const QUrl &url)
+{
+ Q_D(QSGLoader);
+ if (d->source == url)
+ return;
+
+ d->clear();
+
+ d->source = url;
+ if (d->source.isEmpty()) {
+ emit sourceChanged();
+ emit statusChanged();
+ emit progressChanged();
+ emit itemChanged();
+ return;
+ }
+
+ d->component = new QDeclarativeComponent(qmlEngine(this), d->source, this);
+ d->ownComponent = true;
+
+ if (isComponentComplete())
+ d->load();
+}
+
+QDeclarativeComponent *QSGLoader::sourceComponent() const
+{
+ Q_D(const QSGLoader);
+ return d->component;
+}
+
+void QSGLoader::setSourceComponent(QDeclarativeComponent *comp)
+{
+ Q_D(QSGLoader);
+ if (comp == d->component)
+ return;
+
+ d->clear();
+
+ d->component = comp;
+ d->ownComponent = false;
+ if (!d->component) {
+ emit sourceChanged();
+ emit statusChanged();
+ emit progressChanged();
+ emit itemChanged();
+ return;
+ }
+
+ if (isComponentComplete())
+ d->load();
+}
+
+void QSGLoader::resetSourceComponent()
+{
+ setSourceComponent(0);
+}
+
+void QSGLoaderPrivate::load()
+{
+ Q_Q(QSGLoader);
+
+ if (!q->isComponentComplete() || !component)
+ return;
+
+ if (!component->isLoading()) {
+ _q_sourceLoaded();
+ } else {
+ QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
+ q, SLOT(_q_sourceLoaded()));
+ QObject::connect(component, SIGNAL(progressChanged(qreal)),
+ q, SIGNAL(progressChanged()));
+ emit q->statusChanged();
+ emit q->progressChanged();
+ emit q->sourceChanged();
+ emit q->itemChanged();
+ }
+}
+
+void QSGLoaderPrivate::_q_sourceLoaded()
+{
+ Q_Q(QSGLoader);
+
+ if (component) {
+ if (!component->errors().isEmpty()) {
+ QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors());
+ emit q->sourceChanged();
+ emit q->statusChanged();
+ emit q->progressChanged();
+ return;
+ }
+
+ QDeclarativeContext *creationContext = component->creationContext();
+ if (!creationContext) creationContext = qmlContext(q);
+ QDeclarativeContext *ctxt = new QDeclarativeContext(creationContext);
+ ctxt->setContextObject(q);
+
+ QDeclarativeGuard<QDeclarativeComponent> c = component;
+ QObject *obj = component->beginCreate(ctxt);
+ if (component != c) {
+ // component->create could trigger a change in source that causes
+ // component to be set to something else. In that case we just
+ // need to cleanup.
+ if (c)
+ c->completeCreate();
+ delete obj;
+ delete ctxt;
+ return;
+ }
+ if (obj) {
+ item = qobject_cast<QSGItem *>(obj);
+ if (item) {
+ QDeclarative_setParent_noEvent(ctxt, obj);
+ QDeclarative_setParent_noEvent(item, q);
+ item->setParentItem(q);
+// item->setFocus(true);
+ initResize();
+ } else {
+ qmlInfo(q) << QSGLoader::tr("Loader does not support loading non-visual elements.");
+ delete obj;
+ delete ctxt;
+ }
+ } else {
+ if (!component->errors().isEmpty())
+ QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors());
+ delete obj;
+ delete ctxt;
+ source = QUrl();
+ }
+ component->completeCreate();
+ emit q->sourceChanged();
+ emit q->statusChanged();
+ emit q->progressChanged();
+ emit q->itemChanged();
+ emit q->loaded();
+ }
+}
+
+QSGLoader::Status QSGLoader::status() const
+{
+ Q_D(const QSGLoader);
+
+ if (d->component)
+ return static_cast<QSGLoader::Status>(d->component->status());
+
+ if (d->item)
+ return Ready;
+
+ return d->source.isEmpty() ? Null : Error;
+}
+
+void QSGLoader::componentComplete()
+{
+ Q_D(QSGLoader);
+ QSGItem::componentComplete();
+ d->load();
+}
+
+qreal QSGLoader::progress() const
+{
+ Q_D(const QSGLoader);
+
+ if (d->item)
+ return 1.0;
+
+ if (d->component)
+ return d->component->progress();
+
+ return 0.0;
+}
+
+void QSGLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
+{
+ Q_Q(QSGLoader);
+ if (!item || updatingSize)
+ return;
+
+ updatingSize = true;
+
+ if (!itemWidthValid)
+ q->setImplicitWidth(item->implicitWidth());
+ else
+ q->setImplicitWidth(item->width());
+ if (loaderGeometryChanged && q->widthValid())
+ item->setWidth(q->width());
+
+ if (!itemHeightValid)
+ q->setImplicitHeight(item->implicitHeight());
+ else
+ q->setImplicitHeight(item->height());
+ if (loaderGeometryChanged && q->heightValid())
+ item->setHeight(q->height());
+
+ updatingSize = false;
+}
+
+QSGItem *QSGLoader::item() const
+{
+ Q_D(const QSGLoader);
+ return d->item;
+}
+
+void QSGLoader::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QSGLoader);
+ if (newGeometry != oldGeometry) {
+ d->_q_updateSize();
+ }
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+#include <moc_qsgloader_p.cpp>
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgloader_p.h b/src/declarative/items/qsgloader_p.h
new file mode 100644
index 0000000000..689971792c
--- /dev/null
+++ b/src/declarative/items/qsgloader_p.h
@@ -0,0 +1,107 @@
+// Commit: 6f78a6080b84cc3ef96b73a4ff58d1b5a72f08f4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGLOADER_P_H
+#define QSGLOADER_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGLoaderPrivate;
+class Q_AUTOTEST_EXPORT QSGLoader : public QSGImplicitSizeItem
+{
+ Q_OBJECT
+ Q_ENUMS(Status)
+
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(QDeclarativeComponent *sourceComponent READ sourceComponent WRITE setSourceComponent RESET resetSourceComponent NOTIFY sourceChanged)
+ Q_PROPERTY(QSGItem *item READ item NOTIFY itemChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+
+public:
+ QSGLoader(QSGItem *parent=0);
+ virtual ~QSGLoader();
+
+ QUrl source() const;
+ void setSource(const QUrl &);
+
+ QDeclarativeComponent *sourceComponent() const;
+ void setSourceComponent(QDeclarativeComponent *);
+ void resetSourceComponent();
+
+ enum Status { Null, Ready, Loading, Error };
+ Status status() const;
+ qreal progress() const;
+
+ QSGItem *item() const;
+
+Q_SIGNALS:
+ void itemChanged();
+ void sourceChanged();
+ void statusChanged();
+ void progressChanged();
+ void loaded();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ void componentComplete();
+
+private:
+ Q_DISABLE_COPY(QSGLoader)
+ Q_DECLARE_PRIVATE(QSGLoader)
+ Q_PRIVATE_SLOT(d_func(), void _q_sourceLoaded())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateSize())
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGLoader)
+
+QT_END_HEADER
+
+#endif // QSGLOADER_P_H
diff --git a/src/declarative/items/qsgloader_p_p.h b/src/declarative/items/qsgloader_p_p.h
new file mode 100644
index 0000000000..63da789dce
--- /dev/null
+++ b/src/declarative/items/qsgloader_p_p.h
@@ -0,0 +1,91 @@
+// Commit: 5d2817cd668a705729df1727de49adf00713ac97
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGLOADER_P_P_H
+#define QSGLOADER_P_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 "qsgloader_p.h"
+#include "qsgimplicitsizeitem_p_p.h"
+#include "qsgitemchangelistener_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContext;
+class QSGLoaderPrivate : public QSGImplicitSizeItemPrivate, public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGLoader)
+
+public:
+ QSGLoaderPrivate();
+ ~QSGLoaderPrivate();
+
+ void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
+ void clear();
+ void initResize();
+ void load();
+
+ QUrl source;
+ QSGItem *item;
+ QDeclarativeComponent *component;
+ bool ownComponent : 1;
+ bool updatingSize: 1;
+ bool itemWidthValid : 1;
+ bool itemHeightValid : 1;
+
+ void _q_sourceLoaded();
+ void _q_updateSize(bool loaderGeometryChanged = true);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGLOADER_P_P_H
diff --git a/src/declarative/items/qsgmousearea.cpp b/src/declarative/items/qsgmousearea.cpp
new file mode 100644
index 0000000000..1157a9a172
--- /dev/null
+++ b/src/declarative/items/qsgmousearea.cpp
@@ -0,0 +1,771 @@
+// Commit: f0f6deb9a5e8bd078047dd090a3857290c8b4ea4
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmousearea_p.h"
+#include "qsgmousearea_p_p.h"
+#include "qsgcanvas.h"
+#include "qsgevents_p_p.h"
+
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qapplication.h>
+
+#include <float.h>
+
+QT_BEGIN_NAMESPACE
+static const int PressAndHoldDelay = 800;
+
+QSGDrag::QSGDrag(QObject *parent)
+: QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX), _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX),
+_active(false), _filterChildren(false)
+{
+}
+
+QSGDrag::~QSGDrag()
+{
+}
+
+QSGItem *QSGDrag::target() const
+{
+ return _target;
+}
+
+void QSGDrag::setTarget(QSGItem *t)
+{
+ if (_target == t)
+ return;
+ _target = t;
+ emit targetChanged();
+}
+
+void QSGDrag::resetTarget()
+{
+ if (!_target)
+ return;
+ _target = 0;
+ emit targetChanged();
+}
+
+QSGDrag::Axis QSGDrag::axis() const
+{
+ return _axis;
+}
+
+void QSGDrag::setAxis(QSGDrag::Axis a)
+{
+ if (_axis == a)
+ return;
+ _axis = a;
+ emit axisChanged();
+}
+
+qreal QSGDrag::xmin() const
+{
+ return _xmin;
+}
+
+void QSGDrag::setXmin(qreal m)
+{
+ if (_xmin == m)
+ return;
+ _xmin = m;
+ emit minimumXChanged();
+}
+
+qreal QSGDrag::xmax() const
+{
+ return _xmax;
+}
+
+void QSGDrag::setXmax(qreal m)
+{
+ if (_xmax == m)
+ return;
+ _xmax = m;
+ emit maximumXChanged();
+}
+
+qreal QSGDrag::ymin() const
+{
+ return _ymin;
+}
+
+void QSGDrag::setYmin(qreal m)
+{
+ if (_ymin == m)
+ return;
+ _ymin = m;
+ emit minimumYChanged();
+}
+
+qreal QSGDrag::ymax() const
+{
+ return _ymax;
+}
+
+void QSGDrag::setYmax(qreal m)
+{
+ if (_ymax == m)
+ return;
+ _ymax = m;
+ emit maximumYChanged();
+}
+
+bool QSGDrag::active() const
+{
+ return _active;
+}
+
+void QSGDrag::setActive(bool drag)
+{
+ if (_active == drag)
+ return;
+ _active = drag;
+ emit activeChanged();
+}
+
+bool QSGDrag::filterChildren() const
+{
+ return _filterChildren;
+}
+
+void QSGDrag::setFilterChildren(bool filter)
+{
+ if (_filterChildren == filter)
+ return;
+ _filterChildren = filter;
+ emit filterChildrenChanged();
+}
+
+QSGMouseAreaPrivate::QSGMouseAreaPrivate()
+: absorb(true), hovered(false), pressed(false), longPress(false),
+ moved(false), stealMouse(false), doubleClick(false), preventStealing(false), drag(0)
+{
+}
+
+QSGMouseAreaPrivate::~QSGMouseAreaPrivate()
+{
+ delete drag;
+}
+
+void QSGMouseAreaPrivate::init()
+{
+ Q_Q(QSGMouseArea);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFiltersChildMouseEvents(true);
+}
+
+void QSGMouseAreaPrivate::saveEvent(QGraphicsSceneMouseEvent *event)
+{
+ lastPos = event->pos();
+ lastScenePos = event->scenePos();
+ lastButton = event->button();
+ lastButtons = event->buttons();
+ lastModifiers = event->modifiers();
+}
+
+bool QSGMouseAreaPrivate::isPressAndHoldConnected()
+{
+ Q_Q(QSGMouseArea);
+ static int idx = QObjectPrivate::get(q)->signalIndex("pressAndHold(QSGMouseEvent*)");
+ return QObjectPrivate::get(q)->isSignalConnected(idx);
+}
+
+bool QSGMouseAreaPrivate::isDoubleClickConnected()
+{
+ Q_Q(QSGMouseArea);
+ static int idx = QObjectPrivate::get(q)->signalIndex("doubleClicked(QSGMouseEvent*)");
+ return QObjectPrivate::get(q)->isSignalConnected(idx);
+}
+
+bool QSGMouseAreaPrivate::isClickConnected()
+{
+ Q_Q(QSGMouseArea);
+ static int idx = QObjectPrivate::get(q)->signalIndex("clicked(QSGMouseEvent*)");
+ return QObjectPrivate::get(q)->isSignalConnected(idx);
+}
+
+void QSGMouseAreaPrivate::propagate(QSGMouseEvent* event, PropagateType t)
+{
+ Q_Q(QSGMouseArea);
+ QPointF scenePos = q->mapToScene(QPointF(event->x(), event->y()));
+ propagateHelper(event, canvas->rootItem(), scenePos, t);
+}
+
+bool QSGMouseAreaPrivate::propagateHelper(QSGMouseEvent *ev, QSGItem *item,const QPointF &sp, PropagateType sig)
+{
+ //Based off of QSGCanvas::deliverInitialMousePressEvent
+ //But specific to MouseArea, so doesn't belong in canvas
+ Q_Q(const QSGMouseArea);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(sp);
+ if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ return false;
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isVisible() || !child->isEnabled())
+ continue;
+ if (propagateHelper(ev, child, sp, sig))
+ return true;
+ }
+
+ QSGMouseArea* ma = qobject_cast<QSGMouseArea*>(item);
+ if (ma && ma != q && itemPrivate->acceptedMouseButtons & ev->button()) {
+ switch(sig){
+ case Click:
+ if (!ma->d_func()->isClickConnected())
+ return false;
+ break;
+ case DoubleClick:
+ if (!ma->d_func()->isDoubleClickConnected())
+ return false;
+ break;
+ case PressAndHold:
+ if (!ma->d_func()->isPressAndHoldConnected())
+ return false;
+ break;
+ }
+ QPointF p = item->mapFromScene(sp);
+ if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ ev->setX(p.x());
+ ev->setY(p.y());
+ ev->setAccepted(true);//It is connected, they have to explicitly ignore to let it slide
+ switch(sig){
+ case Click: emit ma->clicked(ev); break;
+ case DoubleClick: emit ma->doubleClicked(ev); break;
+ case PressAndHold: emit ma->pressAndHold(ev); break;
+ }
+ if (ev->isAccepted())
+ return true;
+ }
+ }
+ return false;
+
+}
+
+/*
+ Behavioral Change in QtQuick 2.0
+
+ From QtQuick 2.0, the signals clicked, doubleClicked and pressAndHold have a different interaction
+ model with regards to the delivery of events to multiple overlapping MouseAreas. These signals will now propagate
+ to all MouseAreas in the area, in painting order, until accepted by one of them. A signal is accepted by
+ default if there is a signal handler for it, use mouse.accepted = false; to ignore. This propagation
+ can send the signal to MouseAreas other than the one which accepted the press event, although that MouseArea
+ will receive the signal first.
+
+ Note that to get the same behavior as a QtQuick 1.0 MouseArea{} with regard to absorbing all mouse events, you will
+ now need to add empty signal handlers for these three signals.
+ */
+QSGMouseArea::QSGMouseArea(QSGItem *parent)
+ : QSGItem(*(new QSGMouseAreaPrivate), parent)
+{
+ Q_D(QSGMouseArea);
+ d->init();
+}
+
+QSGMouseArea::~QSGMouseArea()
+{
+}
+
+qreal QSGMouseArea::mouseX() const
+{
+ Q_D(const QSGMouseArea);
+ return d->lastPos.x();
+}
+
+qreal QSGMouseArea::mouseY() const
+{
+ Q_D(const QSGMouseArea);
+ return d->lastPos.y();
+}
+
+bool QSGMouseArea::isEnabled() const
+{
+ Q_D(const QSGMouseArea);
+ return d->absorb;
+}
+
+void QSGMouseArea::setEnabled(bool a)
+{
+ Q_D(QSGMouseArea);
+ if (a != d->absorb) {
+ d->absorb = a;
+ emit enabledChanged();
+ }
+}
+
+bool QSGMouseArea::preventStealing() const
+{
+ Q_D(const QSGMouseArea);
+ return d->preventStealing;
+}
+
+void QSGMouseArea::setPreventStealing(bool prevent)
+{
+ Q_D(QSGMouseArea);
+ if (prevent != d->preventStealing) {
+ d->preventStealing = prevent;
+ setKeepMouseGrab(d->preventStealing && d->absorb);
+ emit preventStealingChanged();
+ }
+}
+
+Qt::MouseButtons QSGMouseArea::pressedButtons() const
+{
+ Q_D(const QSGMouseArea);
+ return d->lastButtons;
+}
+
+void QSGMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGMouseArea);
+ d->moved = false;
+ d->stealMouse = d->preventStealing;
+ if (!d->absorb)
+ QSGItem::mousePressEvent(event);
+ else {
+ d->longPress = false;
+ d->saveEvent(event);
+ if (d->drag) {
+ d->dragX = drag()->axis() & QSGDrag::XAxis;
+ d->dragY = drag()->axis() & QSGDrag::YAxis;
+ }
+ if (d->drag)
+ d->drag->setActive(false);
+ setHovered(true);
+ d->startScene = event->scenePos();
+ d->pressAndHoldTimer.start(PressAndHoldDelay, this);
+ setKeepMouseGrab(d->stealMouse);
+ event->setAccepted(setPressed(true));
+ }
+}
+
+void QSGMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb) {
+ QSGItem::mouseMoveEvent(event);
+ return;
+ }
+
+ d->saveEvent(event);
+
+ // ### we should skip this if these signals aren't used
+ // ### can GV handle this for us?
+ bool contains = boundingRect().contains(d->lastPos);
+ if (d->hovered && !contains)
+ setHovered(false);
+ else if (!d->hovered && contains)
+ setHovered(true);
+
+ if (d->drag && d->drag->target()) {
+ if (!d->moved) {
+ d->startX = drag()->target()->x();
+ d->startY = drag()->target()->y();
+ }
+
+ QPointF startLocalPos;
+ QPointF curLocalPos;
+ if (drag()->target()->parentItem()) {
+ startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
+ curLocalPos = drag()->target()->parentItem()->mapFromScene(event->scenePos());
+ } else {
+ startLocalPos = d->startScene;
+ curLocalPos = event->scenePos();
+ }
+
+ const int dragThreshold = QApplication::startDragDistance();
+ qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
+ qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
+
+ if (keepMouseGrab() && d->stealMouse)
+ d->drag->setActive(true);
+
+ if (d->dragX && d->drag->active()) {
+ qreal x = (curLocalPos.x() - startLocalPos.x()) + d->startX;
+ if (x < drag()->xmin())
+ x = drag()->xmin();
+ else if (x > drag()->xmax())
+ x = drag()->xmax();
+ drag()->target()->setX(x);
+ }
+ if (d->dragY && d->drag->active()) {
+ qreal y = (curLocalPos.y() - startLocalPos.y()) + d->startY;
+ if (y < drag()->ymin())
+ y = drag()->ymin();
+ else if (y > drag()->ymax())
+ y = drag()->ymax();
+ drag()->target()->setY(y);
+ }
+
+ if (!keepMouseGrab()) {
+ if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold)
+ || (!d->dragX && dx < dragThreshold && d->dragY && dy > dragThreshold)
+ || (d->dragX && d->dragY && (dx > dragThreshold || dy > dragThreshold))) {
+ setKeepMouseGrab(true);
+ d->stealMouse = true;
+ }
+ }
+
+ d->moved = true;
+ }
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ emit mousePositionChanged(&me);
+ me.setX(d->lastPos.x());
+ me.setY(d->lastPos.y());
+ emit positionChanged(&me);
+}
+
+void QSGMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGMouseArea);
+ d->stealMouse = false;
+ if (!d->absorb) {
+ QSGItem::mouseReleaseEvent(event);
+ } else {
+ d->saveEvent(event);
+ setPressed(false);
+ if (d->drag)
+ d->drag->setActive(false);
+ // If we don't accept hover, we need to reset containsMouse.
+ if (!acceptHoverEvents())
+ setHovered(false);
+ QSGCanvas *c = canvas();
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+ }
+ d->doubleClick = false;
+}
+
+void QSGMouseArea::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb) {
+ QSGItem::mouseDoubleClickEvent(event);
+ } else {
+ d->saveEvent(event);
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
+ me.setAccepted(d->isDoubleClickConnected());
+ emit this->doubleClicked(&me);
+ if (!me.isAccepted())
+ d->propagate(&me, QSGMouseAreaPrivate::DoubleClick);
+ d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
+ QSGItem::mouseDoubleClickEvent(event);
+ }
+}
+
+void QSGMouseArea::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb) {
+ QSGItem::hoverEnterEvent(event);
+ } else {
+ d->lastPos = event->pos();
+ setHovered(true);
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
+ emit mousePositionChanged(&me);
+ }
+}
+
+void QSGMouseArea::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb) {
+ QSGItem::hoverMoveEvent(event);
+ } else {
+ d->lastPos = event->pos();
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
+ emit mousePositionChanged(&me);
+ me.setX(d->lastPos.x());
+ me.setY(d->lastPos.y());
+ emit positionChanged(&me);
+ }
+}
+
+void QSGMouseArea::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb)
+ QSGItem::hoverLeaveEvent(event);
+ else
+ setHovered(false);
+}
+
+void QSGMouseArea::mouseUngrabEvent()
+{
+ Q_D(QSGMouseArea);
+ if (d->pressed) {
+ // if our mouse grab has been removed (probably by Flickable), fix our
+ // state
+ d->pressed = false;
+ d->stealMouse = false;
+ setKeepMouseGrab(false);
+ emit canceled();
+ emit pressedChanged();
+ if (d->hovered) {
+ d->hovered = false;
+ emit hoveredChanged();
+ }
+ }
+}
+
+bool QSGMouseArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGMouseArea);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+
+ QSGCanvas *c = canvas();
+ QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ mouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ mousePressEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ mouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = c->mouseGrabberItem();
+ if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ return stealThisEvent;
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+ if (d->pressed) {
+ d->pressed = false;
+ d->stealMouse = false;
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ emit canceled();
+ emit pressedChanged();
+ if (d->hovered) {
+ d->hovered = false;
+ emit hoveredChanged();
+ }
+ }
+ }
+ return false;
+}
+
+bool QSGMouseArea::childMouseEventFilter(QSGItem *i, QEvent *e)
+{
+ Q_D(QSGMouseArea);
+ if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
+ return QSGItem::childMouseEventFilter(i, e);
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ default:
+ break;
+ }
+
+ return QSGItem::childMouseEventFilter(i, e);
+}
+
+void QSGMouseArea::timerEvent(QTimerEvent *event)
+{
+ Q_D(QSGMouseArea);
+ if (event->timerId() == d->pressAndHoldTimer.timerId()) {
+ d->pressAndHoldTimer.stop();
+ bool dragged = d->drag && d->drag->active();
+ if (d->pressed && dragged == false && d->hovered == true) {
+ d->longPress = true;
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ me.setAccepted(d->isPressAndHoldConnected());
+ emit pressAndHold(&me);
+ if (!me.isAccepted())
+ d->propagate(&me, QSGMouseAreaPrivate::PressAndHold);
+ }
+ }
+}
+
+void QSGMouseArea::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QSGMouseArea);
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+
+ if (d->lastScenePos.isNull)
+ d->lastScenePos = mapToScene(d->lastPos);
+ else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
+ d->lastPos = mapFromScene(d->lastScenePos);
+}
+
+void QSGMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QSGMouseArea);
+ switch (change) {
+ case ItemVisibleHasChanged:
+ if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
+ setHovered(!d->hovered);
+ break;
+ default:
+ break;
+ }
+
+ QSGItem::itemChange(change, value);
+}
+
+bool QSGMouseArea::hoverEnabled() const
+{
+ return acceptHoverEvents();
+}
+
+void QSGMouseArea::setHoverEnabled(bool h)
+{
+ Q_D(QSGMouseArea);
+ if (h == acceptHoverEvents())
+ return;
+
+ setAcceptHoverEvents(h);
+ emit hoverEnabledChanged();
+ if (d->hovered != isUnderMouse())
+ setHovered(!d->hovered);
+}
+
+bool QSGMouseArea::hovered() const
+{
+ Q_D(const QSGMouseArea);
+ return d->hovered;
+}
+
+bool QSGMouseArea::pressed() const
+{
+ Q_D(const QSGMouseArea);
+ return d->pressed;
+}
+
+void QSGMouseArea::setHovered(bool h)
+{
+ Q_D(QSGMouseArea);
+ if (d->hovered != h) {
+ d->hovered = h;
+ emit hoveredChanged();
+ d->hovered ? emit entered() : emit exited();
+ }
+}
+
+Qt::MouseButtons QSGMouseArea::acceptedButtons() const
+{
+ return acceptedMouseButtons();
+}
+
+void QSGMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
+{
+ if (buttons != acceptedMouseButtons()) {
+ setAcceptedMouseButtons(buttons);
+ emit acceptedButtonsChanged();
+ }
+}
+
+bool QSGMouseArea::setPressed(bool p)
+{
+ Q_D(QSGMouseArea);
+ bool dragged = d->drag && d->drag->active();
+ bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
+
+ if (d->pressed != p) {
+ d->pressed = p;
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
+ if (d->pressed) {
+ if (!d->doubleClick)
+ emit pressed(&me);
+ me.setX(d->lastPos.x());
+ me.setY(d->lastPos.y());
+ emit mousePositionChanged(&me);
+ emit pressedChanged();
+ } else {
+ emit released(&me);
+ me.setX(d->lastPos.x());
+ me.setY(d->lastPos.y());
+ emit pressedChanged();
+ if (isclick && !d->longPress && !d->doubleClick){
+ me.setAccepted(d->isClickConnected());
+ emit clicked(&me);
+ if (!me.isAccepted())
+ d->propagate(&me, QSGMouseAreaPrivate::Click);
+ }
+ }
+
+ return me.isAccepted();
+ }
+ return false;
+}
+
+QSGDrag *QSGMouseArea::drag()
+{
+ Q_D(QSGMouseArea);
+ if (!d->drag)
+ d->drag = new QSGDrag;
+ return d->drag;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgmousearea_p.h b/src/declarative/items/qsgmousearea_p.h
new file mode 100644
index 0000000000..24fb8389a6
--- /dev/null
+++ b/src/declarative/items/qsgmousearea_p.h
@@ -0,0 +1,216 @@
+// Commit: 57676c237992e0aa5a93a4e8fa66b3e7b90c2c90
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGMOUSEAREA_P_H
+#define QSGMOUSEAREA_P_H
+
+#include "qsgitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QSGDrag : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(Axis)
+ Q_PROPERTY(QSGItem *target READ target WRITE setTarget NOTIFY targetChanged RESET resetTarget)
+ Q_PROPERTY(Axis axis READ axis WRITE setAxis NOTIFY axisChanged)
+ Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged)
+ Q_PROPERTY(qreal maximumX READ xmax WRITE setXmax NOTIFY maximumXChanged)
+ 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)
+ Q_PROPERTY(bool filterChildren READ filterChildren WRITE setFilterChildren NOTIFY filterChildrenChanged)
+ //### consider drag and drop
+
+public:
+ QSGDrag(QObject *parent=0);
+ ~QSGDrag();
+
+ QSGItem *target() const;
+ void setTarget(QSGItem *);
+ void resetTarget();
+
+ enum Axis { XAxis=0x01, YAxis=0x02, XandYAxis=0x03 };
+ Axis axis() const;
+ void setAxis(Axis);
+
+ qreal xmin() const;
+ void setXmin(qreal);
+ qreal xmax() const;
+ void setXmax(qreal);
+ qreal ymin() const;
+ void setYmin(qreal);
+ qreal ymax() const;
+ void setYmax(qreal);
+
+ bool active() const;
+ void setActive(bool);
+
+ bool filterChildren() const;
+ void setFilterChildren(bool);
+
+Q_SIGNALS:
+ void targetChanged();
+ void axisChanged();
+ void minimumXChanged();
+ void maximumXChanged();
+ void minimumYChanged();
+ void maximumYChanged();
+ void activeChanged();
+ void filterChildrenChanged();
+
+private:
+ QSGItem *_target;
+ Axis _axis;
+ qreal _xmin;
+ qreal _xmax;
+ qreal _ymin;
+ qreal _ymax;
+ bool _active : 1;
+ bool _filterChildren: 1;
+ Q_DISABLE_COPY(QSGDrag)
+};
+
+class QSGMouseEvent;
+class QSGMouseAreaPrivate;
+class Q_AUTOTEST_EXPORT QSGMouseArea : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal mouseX READ mouseX NOTIFY mousePositionChanged)
+ Q_PROPERTY(qreal mouseY READ mouseY NOTIFY mousePositionChanged)
+ Q_PROPERTY(bool containsMouse READ hovered NOTIFY hoveredChanged)
+ Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons NOTIFY pressedChanged)
+ Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged)
+ Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged)
+ Q_PROPERTY(QSGDrag *drag READ drag CONSTANT) //### add flicking to QSGDrag or add a QDeclarativeFlick ???
+ Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged)
+
+public:
+ QSGMouseArea(QSGItem *parent=0);
+ ~QSGMouseArea();
+
+ qreal mouseX() const;
+ qreal mouseY() const;
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ bool hovered() const;
+ bool pressed() const;
+
+ Qt::MouseButtons pressedButtons() const;
+
+ Qt::MouseButtons acceptedButtons() const;
+ void setAcceptedButtons(Qt::MouseButtons buttons);
+
+ bool hoverEnabled() const;
+ void setHoverEnabled(bool h);
+
+ QSGDrag *drag();
+
+ bool preventStealing() const;
+ void setPreventStealing(bool prevent);
+
+Q_SIGNALS:
+ void hoveredChanged();
+ void pressedChanged();
+ void enabledChanged();
+ void acceptedButtonsChanged();
+ void hoverEnabledChanged();
+ void positionChanged(QSGMouseEvent *mouse);
+ void mousePositionChanged(QSGMouseEvent *mouse);
+ void preventStealingChanged();
+
+ void pressed(QSGMouseEvent *mouse);
+ void pressAndHold(QSGMouseEvent *mouse);
+ void released(QSGMouseEvent *mouse);
+ void clicked(QSGMouseEvent *mouse);
+ void doubleClicked(QSGMouseEvent *mouse);
+ void entered();
+ void exited();
+ void canceled();
+
+protected:
+ void setHovered(bool);
+ bool setPressed(bool);
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseUngrabEvent();
+ virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ virtual bool childMouseEventFilter(QSGItem *i, QEvent *e);
+ virtual void timerEvent(QTimerEvent *event);
+
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ virtual void itemChange(ItemChange change, const ItemChangeData& value);
+
+private:
+ void handlePress();
+ void handleRelease();
+
+private:
+ Q_DISABLE_COPY(QSGMouseArea)
+ Q_DECLARE_PRIVATE(QSGMouseArea)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGDrag)
+QML_DECLARE_TYPE(QSGMouseArea)
+
+QT_END_HEADER
+
+#endif // QSGMOUSEAREA_P_H
diff --git a/src/declarative/items/qsgmousearea_p_p.h b/src/declarative/items/qsgmousearea_p_p.h
new file mode 100644
index 0000000000..b4b64c67e9
--- /dev/null
+++ b/src/declarative/items/qsgmousearea_p_p.h
@@ -0,0 +1,112 @@
+// Commit: 57676c237992e0aa5a93a4e8fa66b3e7b90c2c90
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGMOUSEAREA_P_P_H
+#define QSGMOUSEAREA_P_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 "qsgitem_p.h"
+
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtCore/qbasictimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGMouseEvent;
+class QSGMouseArea;
+class QSGMouseAreaPrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGMouseArea)
+
+public:
+ QSGMouseAreaPrivate();
+ ~QSGMouseAreaPrivate();
+ void init();
+
+ void saveEvent(QGraphicsSceneMouseEvent *event);
+ enum PropagateType{
+ Click,
+ DoubleClick,
+ PressAndHold
+ };
+ void propagate(QSGMouseEvent* event, PropagateType);
+ bool propagateHelper(QSGMouseEvent*, QSGItem*,const QPointF &, PropagateType);
+
+ bool isPressAndHoldConnected();
+ bool isDoubleClickConnected();
+ bool isClickConnected();
+
+ bool absorb : 1;
+ bool hovered : 1;
+ bool pressed : 1;
+ bool longPress : 1;
+ bool moved : 1;
+ bool dragX : 1;
+ bool dragY : 1;
+ bool stealMouse : 1;
+ bool doubleClick : 1;
+ bool preventStealing : 1;
+ QSGDrag *drag;
+ QPointF startScene;
+ qreal startX;
+ qreal startY;
+ QPointF lastPos;
+ QDeclarativeNullableValue<QPointF> lastScenePos;
+ Qt::MouseButton lastButton;
+ Qt::MouseButtons lastButtons;
+ Qt::KeyboardModifiers lastModifiers;
+ QBasicTimer pressAndHoldTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGMOUSEAREA_P_P_H
diff --git a/src/declarative/items/qsgninepatchnode.cpp b/src/declarative/items/qsgninepatchnode.cpp
new file mode 100644
index 0000000000..7858e98190
--- /dev/null
+++ b/src/declarative/items/qsgninepatchnode.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgninepatchnode_p.h"
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qmath_p.h>
+
+QSGNinePatchNode::QSGNinePatchNode()
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
+ , m_horizontalTileMode(QSGBorderImage::Stretch)
+ , m_verticalTileMode(QSGBorderImage::Stretch)
+ , m_dirtyGeometry(false)
+{
+ setOpaqueMaterial(&m_material);
+ setMaterial(&m_materialO);
+ setGeometry(&m_geometry);
+ m_geometry.setDrawingMode(GL_TRIANGLES);
+}
+
+void QSGNinePatchNode::setInnerRect(const QRectF &rect)
+{
+ if (m_innerRect == rect)
+ return;
+ m_innerRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGNinePatchNode::setRect(const QRectF &rect)
+{
+ if (m_targetRect == rect)
+ return;
+ m_targetRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGNinePatchNode::setHorzontalTileMode(QSGBorderImage::TileMode mode)
+{
+ if (mode == QSGBorderImage::TileMode(m_horizontalTileMode))
+ return;
+ m_horizontalTileMode = mode;
+ m_dirtyGeometry = true;
+}
+
+
+void QSGNinePatchNode::setVerticalTileMode(QSGBorderImage::TileMode mode)
+{
+ if (mode == QSGBorderImage::TileMode(m_verticalTileMode))
+ return;
+ m_verticalTileMode = mode;
+ m_dirtyGeometry = true;
+}
+
+
+void QSGNinePatchNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.filtering() == filtering)
+ return;
+
+ m_material.setFiltering(filtering);
+ m_materialO.setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+QSGTexture::Filtering QSGNinePatchNode::filtering() const
+{
+ return m_material.filtering();
+}
+
+void QSGNinePatchNode::setTexture(QSGTexture *texture)
+{
+ if (texture == m_material.texture())
+ return;
+ m_material.setTexture(texture);
+ m_materialO.setTexture(texture);
+ markDirty(DirtyMaterial);
+}
+
+QSGTexture *QSGNinePatchNode::texture() const
+{
+ return m_material.texture();
+}
+
+void QSGNinePatchNode::update()
+{
+ if (!m_dirtyGeometry)
+ return;
+
+ // For stretch this algorithm could be simplified to use less vertices
+ // as more vertices could be reused then, but I doubt its where our main
+ // problem will lie. This way, we at least share the algorithm between all
+
+ Q_ASSERT(m_material.texture());
+
+ float tw = m_material.texture()->textureSize().width();
+ float th = m_material.texture()->textureSize().height();
+
+ float rightBorder = tw - m_innerRect.right();
+ float bottomBorder = th - m_innerRect.bottom();
+
+// qDebug() << m_innerRect << m_targetRect << m_horizontalTileMode << m_verticalTileMode;
+
+ int xChunkCount = 0; // Number of chunks
+ float xChunkSize = 0; // Size of chunk in pixels
+ float xTexSize = m_innerRect.width(); // Size of the texture to stretch/tile
+ float xSize = m_targetRect.width() - m_innerRect.left() - rightBorder; // Size of area to fill with chunks
+
+ if (m_horizontalTileMode == QSGBorderImage::Repeat) {
+ xChunkCount = qCeil(xSize / xTexSize);
+ xChunkSize = xTexSize;
+ } else if (m_horizontalTileMode == QSGBorderImage::Round) {
+ xChunkCount = qCeil(xSize / xTexSize);
+ xChunkSize = xSize / xChunkCount;
+ } else {
+ xChunkCount = 1;
+ xChunkSize = xSize;
+ }
+
+ int yChunkCount = 0;
+ float yChunkSize = 0; // Relative to target rect.
+ float yTexSize = m_innerRect.height(); // Size of the texture to stretch/tile
+ float ySize = m_targetRect.height() - m_innerRect.top() - bottomBorder;
+
+ if (m_verticalTileMode == QSGBorderImage::Repeat) {
+ yChunkCount = qCeil(ySize / yTexSize);
+ yChunkSize = yTexSize;
+ } else if (m_verticalTileMode == QSGBorderImage::Round) {
+ yChunkCount = qCeil(ySize / yTexSize);
+ yChunkSize = ySize / yChunkCount;
+ } else {
+ yChunkCount = 1;
+ yChunkSize = ySize;
+ }
+
+ int xTotalChunkCount = xChunkCount + 2;
+ int yTotalChunkCount = yChunkCount + 2;
+
+ int totalChunkCount = xTotalChunkCount * yTotalChunkCount;
+ int vertexCount = totalChunkCount * 4;
+ int indexCount = totalChunkCount * 6;
+
+ if (vertexCount != m_geometry.vertexCount() || indexCount != m_geometry.indexCount())
+ m_geometry.allocate(vertexCount, indexCount);
+
+ QSGGeometry::TexturedPoint2D *v = m_geometry.vertexDataAsTexturedPoint2D();
+
+
+ // Fill in the vertices.. The loop below is pretty much an exact replica
+ // of the one inside fillRow.
+ float yTexChunk1 = 1 - m_innerRect.top() / th;
+ float yTexChunk2 = 1 - m_innerRect.bottom() / th;
+
+ fillRow(v, 0, 1, xChunkCount, xChunkSize);
+ fillRow(v, m_innerRect.y(), yTexChunk1, xChunkCount, xChunkSize);
+
+ for (int yc=0; yc<yChunkCount; ++yc) {
+ float yy = m_innerRect.y() + yChunkSize * yc;
+ fillRow(v, yy, yTexChunk1, xChunkCount, xChunkSize);
+
+ // Special case the last one
+ if (yc == yChunkCount - 1) {
+ float t = m_verticalTileMode == QSGBorderImage::Repeat
+ ? yTexChunk1 + (yTexChunk2 - yTexChunk1) * (m_targetRect.height() - bottomBorder - yy) / yChunkSize
+ : yTexChunk2;
+ fillRow(v, m_targetRect.height() - bottomBorder, t, xChunkCount, xChunkSize);
+ } else {
+ fillRow(v, yy + yChunkSize, yTexChunk2, xChunkCount, xChunkSize);
+ }
+ }
+
+ fillRow(v, m_targetRect.height() - bottomBorder, yTexChunk2, xChunkCount, xChunkSize);
+ fillRow(v, m_targetRect.height(), 0, xChunkCount, xChunkSize);
+
+
+// v = m_geometry.vertexDataAsTexturedPoint2D();
+// for (int i=0; i<m_geometry.vertexCount(); ++i) {
+// printf("Vertex: %d: (%.3f, %.3f) - (%.3f, %.3f)\n",
+// i,
+// v->x, v->y, v->tx, v->ty);
+// ++v;
+// }
+
+ quint16 *i = m_geometry.indexDataAsUShort();
+ int row = xTotalChunkCount * 2;
+ for (int r=0; r<yTotalChunkCount; ++r) {
+ int offset = r * row * 2;
+ for (int c=0; c<xTotalChunkCount; ++c) {
+ *i++ = offset + c * 2;
+ *i++ = offset + c * 2 + 1;
+ *i++ = offset + c * 2 + row;
+ *i++ = offset + c * 2 + 1;
+ *i++ = offset + c * 2 + row + 1;
+ *i++ = offset + c * 2 + row;
+ }
+ }
+
+// i = m_geometry.indexDataAsUShort();
+// for (int idx=0; idx<m_geometry.indexCount(); idx+=6) {
+// printf("%2d: ", idx / 6);
+// for (int s=0; s<6; ++s)
+// printf(" %d", i[idx + s]);
+// printf("\n");
+// }
+
+ markDirty(QSGNode::DirtyGeometry);
+}
+
+void QSGNinePatchNode::fillRow(QSGGeometry::TexturedPoint2D *&v, float y, float ty, int xChunkCount, float xChunkSize)
+{
+ float tw = m_material.texture()->textureSize().width();
+ float rightBorder = tw - m_innerRect.right();
+ float xTexChunk1 = m_innerRect.left() / tw;
+ float xTexChunk2 = m_innerRect.right() / tw;
+
+ v++->set(0, y, 0, ty);
+ v++->set(m_innerRect.x(), y, xTexChunk1, ty);
+
+ for (int xc=0; xc<xChunkCount; ++xc) {
+ float xx = m_innerRect.x() + xChunkSize * xc;
+ v++->set(xx, y, xTexChunk1, ty);
+
+ // Special case the last one
+ if (xc == xChunkCount - 1) {
+ float t = m_horizontalTileMode == QSGBorderImage::Repeat
+ ? xTexChunk1 + (xTexChunk2 - xTexChunk1) * (m_targetRect.width() - rightBorder - xx) / xChunkSize
+ : xTexChunk2;
+ v->set(m_targetRect.width() - rightBorder, y, t, ty);
+ } else {
+ v->set(xx + xChunkSize, y, xTexChunk2, ty);
+ }
+ ++v;
+ }
+
+ v++->set(m_targetRect.width() - rightBorder, y, xTexChunk2, ty);
+ v++->set(m_targetRect.width(), y, 1, ty);
+}
diff --git a/src/declarative/items/qsgninepatchnode_p.h b/src/declarative/items/qsgninepatchnode_p.h
new file mode 100644
index 0000000000..533495d3ce
--- /dev/null
+++ b/src/declarative/items/qsgninepatchnode_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGNINEPATCHNODE_H
+#define QSGNINEPATCHNODE_H
+
+#include "qsgnode.h"
+#include "qsgtexturematerial.h"
+#include "qsgborderimage_p.h"
+
+class TextureReference;
+
+class QSGNinePatchNode : public QSGGeometryNode
+{
+public:
+ QSGNinePatchNode();
+
+ void setTexture(QSGTexture *texture);
+ QSGTexture *texture() const;
+
+ void setRect(const QRectF &rect);
+ QRectF rect() const { return m_targetRect; }
+
+ void setInnerRect(const QRectF &rect);
+ QRectF innerRect() const { return m_innerRect; }
+
+ void setFiltering(QSGTexture::Filtering filtering);
+ QSGTexture::Filtering filtering() const;
+
+ void setHorzontalTileMode(QSGBorderImage::TileMode mode);
+ QSGBorderImage::TileMode horizontalTileMode() const {
+ return (QSGBorderImage::TileMode) m_horizontalTileMode;
+ }
+
+ void setVerticalTileMode(QSGBorderImage::TileMode mode);
+ QSGBorderImage::TileMode verticalTileMode() const {
+ return (QSGBorderImage::TileMode) m_verticalTileMode;
+ }
+
+ void update();
+
+private:
+ void fillRow(QSGGeometry::TexturedPoint2D *&v, float y, float ty, int xChunkCount, float xChunkSize);
+ QRectF m_targetRect;
+ QRectF m_innerRect;
+ QSGTextureMaterial m_material;
+ QSGTextureMaterialWithOpacity m_materialO;
+ QSGGeometry m_geometry;
+
+ uint m_horizontalTileMode : 2;
+ uint m_verticalTileMode : 2;
+
+ uint m_dirtyGeometry : 1;
+};
+
+#endif // QSGNINEPATCHNODE_H
diff --git a/src/declarative/items/qsgpainteditem.cpp b/src/declarative/items/qsgpainteditem.cpp
new file mode 100644
index 0000000000..8eb8afe8be
--- /dev/null
+++ b/src/declarative/items/qsgpainteditem.cpp
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpainteditem.h"
+#include <private/qsgpainteditem_p.h>
+#include <private/qsgpainternode_p.h>
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGPaintedItem
+ \brief The QSGPaintedItem class provides a way to use the QPainter API in the
+ QML Scene Graph.
+
+ The QSGPaintedItem makes it possible to use the QPainter API with the QML Scene Graph.
+ It sets up a textured rectangle in the Scene Graph and uses a QPainter to paint
+ onto the texture. The render target can be either a QImage or a QGLFramebufferObject.
+ When the render target is a QImage, QPainter first renders into the image then
+ the content is uploaded to the texture.
+ When a QGLFramebufferObject is used, QPainter paints directly onto the texture.
+ Call update() to trigger a repaint.
+
+ Set the \l smooth property to true to enable QPainter to do anti-aliased rendering.
+
+ QSGPaintedItem is meant to make it easier to port old code that is using the
+ QPainter API to the QML Scene Graph API and it should be used only for that purpose.
+
+ To write your own painted item, you first create a subclass of QSGPaintedItem, and then
+ start by implementing its only pure virtual public function: paint(), which implements
+ the actual painting. To get the size of the area painted by the item, use
+ QSGItem::width() and QSGItem::height().
+*/
+
+/*!
+ \enum QSGPaintedItem::RenderTarget
+
+ This enum describes QSGPaintedItem's render targets. The render target is the
+ surface QPainter paints onto before the item is rendered on screen.
+
+ \value Image The default; QPainter paints into a QImage using the raster paint engine.
+ The image's content needs to be uploaded to graphics memory afterward, this operation
+ can potentially be slow if the item is large. This render target allows high quality
+ anti-aliasing and fast item resizing.
+
+ \value FramebufferObject QPainter paints into a QGLFramebufferObject using the GL
+ paint engine. Painting can be faster as no texture upload is required, but anti-aliasing
+ quality is not as good as if using an image. This render target allows faster rendering
+ in some cases, but you should avoid using it if the item is resized often.
+
+ \sa setRenderTarget()
+*/
+
+/*!
+ \internal
+*/
+QSGPaintedItemPrivate::QSGPaintedItemPrivate()
+ : QSGItemPrivate()
+ , fillColor(Qt::transparent)
+ , renderTarget(QSGPaintedItem::Image)
+ , geometryDirty(false)
+ , contentsDirty(false)
+ , opaquePainting(false)
+{
+}
+
+/*!
+ Constructs a QSGPaintedItem with the given \a parent item.
+ */
+QSGPaintedItem::QSGPaintedItem(QSGItem *parent)
+ : QSGItem(*(new QSGPaintedItemPrivate), parent)
+{
+ setFlag(ItemHasContents);
+}
+
+/*!
+ \internal
+*/
+QSGPaintedItem::QSGPaintedItem(QSGPaintedItemPrivate &dd, QSGItem *parent)
+ : QSGItem(dd, parent)
+{
+ setFlag(ItemHasContents);
+}
+
+/*!
+ Destroys the QSGPaintedItem.
+*/
+QSGPaintedItem::~QSGPaintedItem()
+{
+}
+
+/*!
+ Schedules a redraw of the area covered by \a rect in this item. You can call this function
+ whenever your item needs to be redrawn, such as if it changes appearance or size.
+
+ This function does not cause an immediate paint; instead it schedules a paint request that
+ is processed by the QML Scene Graph when the next frame is rendered. The item will only be
+ redrawn if it is visible.
+
+ Note that calling this function will trigger a repaint of the whole scene.
+
+ \sa paint()
+*/
+void QSGPaintedItem::update(const QRect &rect)
+{
+ Q_D(QSGPaintedItem);
+ d->contentsDirty = true;
+ if (rect.isNull() && !d->dirtyRect.isNull())
+ d->dirtyRect = boundingRect().toAlignedRect();
+ else
+ d->dirtyRect |= (boundingRect() & rect).toAlignedRect();
+ QSGItem::update();
+}
+
+/*!
+ Returns true if this item is opaque; otherwise, false is returned.
+
+ By default, painted items are not opaque.
+
+ \sa setOpaquePainting()
+*/
+bool QSGPaintedItem::opaquePainting() const
+{
+ Q_D(const QSGPaintedItem);
+ return d->opaquePainting;
+}
+
+/*!
+ If \a opaque is true, the item is opaque; otherwise, it is considered as translucent.
+
+ Opaque items are not blended with the rest of the scene, you should set this to true
+ if the content of the item is opaque to speed up rendering.
+
+ By default, painted items are not opaque.
+
+ \sa opaquePainting()
+*/
+void QSGPaintedItem::setOpaquePainting(bool opaque)
+{
+ Q_D(QSGPaintedItem);
+
+ if (d->opaquePainting == opaque)
+ return;
+
+ d->opaquePainting = opaque;
+ QSGItem::update();
+}
+
+QSize QSGPaintedItem::contentsSize() const
+{
+ // XXX todo
+ return QSize();
+}
+
+void QSGPaintedItem::setContentsSize(const QSize &)
+{
+ // XXX todo
+}
+
+void QSGPaintedItem::resetContentsSize()
+{
+ // XXX todo
+}
+
+qreal QSGPaintedItem::contentsScale() const
+{
+ // XXX todo
+ return 1;
+}
+
+void QSGPaintedItem::setContentsScale(qreal)
+{
+ // XXX todo
+}
+
+int QSGPaintedItem::pixelCacheSize() const
+{
+ // XXX todo
+ return 0;
+}
+
+void QSGPaintedItem::setPixelCacheSize(int)
+{
+ // XXX todo
+}
+
+bool QSGPaintedItem::smoothCache() const
+{
+ // XXX todo
+ return false;
+}
+
+void QSGPaintedItem::setSmoothCache(bool)
+{
+ // XXX todo
+}
+
+/*!
+ \property QSGPaintedItem::fillColor
+ \brief The item's background fill color.
+
+ By default, the fill color is set to Qt::transparent.
+*/
+QColor QSGPaintedItem::fillColor() const
+{
+ Q_D(const QSGPaintedItem);
+ return d->fillColor;
+}
+
+void QSGPaintedItem::setFillColor(const QColor &c)
+{
+ Q_D(QSGPaintedItem);
+
+ if (d->fillColor == c)
+ return;
+
+ d->fillColor = c;
+ update();
+
+ emit fillColorChanged();
+}
+
+/*!
+ \property QSGPaintedItem::renderTarget
+ \brief The item's render target.
+
+ This property defines which render target the QPainter renders into, it can be either
+ QSGPaintedItem::Image or QSGPaintedItem::FramebufferObject. Both have certains benefits,
+ typically performance versus quality. Using a framebuffer object avoids a costly upload
+ of the image contents to the texture in graphics memory, while using an image enables
+ high quality anti-aliasing.
+
+ \warning Resizing a framebuffer object is a costly operation, avoid using
+ the QSGPaintedItem::FramebufferObject render target if the item gets resized often.
+
+ By default, the render target is QSGPaintedItem::Image.
+*/
+QSGPaintedItem::RenderTarget QSGPaintedItem::renderTarget() const
+{
+ Q_D(const QSGPaintedItem);
+ return d->renderTarget;
+}
+
+void QSGPaintedItem::setRenderTarget(RenderTarget target)
+{
+ Q_D(QSGPaintedItem);
+
+ if (d->renderTarget == target)
+ return;
+
+ d->renderTarget = target;
+ update();
+
+ emit renderTargetChanged();
+}
+
+/*!
+ \fn virtual void QSGPaintedItem::paint(QPainter *painter) = 0
+
+ This function, which is usually called by the QML Scene Graph, paints the
+ contents of an item in local coordinates.
+
+ The function is called after the item has been filled with the fillColor.
+
+ Reimplement this function in a QSGPaintedItem subclass to provide the
+ item's painting implementation, using \a painter.
+*/
+
+/*!
+ This function is called after the item's geometry has changed.
+*/
+void QSGPaintedItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QSGPaintedItem);
+ d->geometryDirty = true;
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+
+/*!
+ This function is called when the Scene Graph node associated to the item needs to
+ be updated.
+*/
+QSGNode *QSGPaintedItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+ Q_D(QSGPaintedItem);
+
+ if (width() <= 0 || height() <= 0) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGPainterNode *node = static_cast<QSGPainterNode *>(oldNode);
+ if (!node)
+ node = new QSGPainterNode(this);
+
+ node->setPreferredRenderTarget(d->renderTarget);
+ node->setSize(QSize(d->width, d->height));
+ node->setSmoothPainting(d->smooth);
+ node->setLinearFiltering(d->smooth);
+ node->setOpaquePainting(d->opaquePainting);
+ node->setFillColor(d->fillColor);
+ node->setDirty(d->contentsDirty || d->geometryDirty, d->dirtyRect);
+ node->update();
+
+ d->contentsDirty = false;
+ d->geometryDirty = false;
+ d->dirtyRect = QRect();
+
+ return node;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgpainteditem.h b/src/declarative/items/qsgpainteditem.h
new file mode 100644
index 0000000000..23becfefa4
--- /dev/null
+++ b/src/declarative/items/qsgpainteditem.h
@@ -0,0 +1,119 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPAINTEDITEM_P_H
+#define QSGPAINTEDITEM_P_H
+
+#include <qsgitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGPaintedItemPrivate;
+class Q_DECLARATIVE_EXPORT QSGPaintedItem : public QSGItem
+{
+ Q_OBJECT
+ Q_ENUMS(RenderTarget)
+
+ Q_PROPERTY(QSize contentsSize READ contentsSize WRITE setContentsSize NOTIFY contentsSizeChanged)
+ Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor NOTIFY fillColorChanged)
+ Q_PROPERTY(int pixelCacheSize READ pixelCacheSize WRITE setPixelCacheSize)
+ Q_PROPERTY(bool smoothCache READ smoothCache WRITE setSmoothCache)
+ Q_PROPERTY(qreal contentsScale READ contentsScale WRITE setContentsScale NOTIFY contentsScaleChanged)
+ Q_PROPERTY(RenderTarget renderTarget READ renderTarget WRITE setRenderTarget NOTIFY renderTargetChanged)
+public:
+ QSGPaintedItem(QSGItem *parent = 0);
+ virtual ~QSGPaintedItem();
+
+ enum RenderTarget {
+ Image,
+ FramebufferObject
+ };
+
+ void update(const QRect &rect = QRect());
+
+ bool opaquePainting() const;
+ void setOpaquePainting(bool opaque);
+
+ QSize contentsSize() const;
+ void setContentsSize(const QSize &);
+ void resetContentsSize();
+
+ qreal contentsScale() const;
+ void setContentsScale(qreal);
+
+ int pixelCacheSize() const;
+ void setPixelCacheSize(int pixels);
+
+ bool smoothCache() const;
+ void setSmoothCache(bool on);
+
+ QColor fillColor() const;
+ void setFillColor(const QColor&);
+
+ RenderTarget renderTarget() const;
+ void setRenderTarget(RenderTarget target);
+
+ virtual void paint(QPainter *painter) = 0;
+
+Q_SIGNALS:
+ void fillColorChanged();
+ void contentsSizeChanged();
+ void contentsScaleChanged();
+ void renderTargetChanged();
+
+protected:
+ QSGPaintedItem(QSGPaintedItemPrivate &dd, QSGItem *parent = 0);
+ virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private:
+ Q_DISABLE_COPY(QSGPaintedItem);
+ Q_DECLARE_PRIVATE(QSGPaintedItem);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGPAINTEDITEM_P_H
diff --git a/src/declarative/items/qsgpainteditem_p.h b/src/declarative/items/qsgpainteditem_p.h
new file mode 100644
index 0000000000..c49da5098f
--- /dev/null
+++ b/src/declarative/items/qsgpainteditem_p.h
@@ -0,0 +1,67 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPAINTEDITEM_P_P_H
+#define QSGPAINTEDITEM_P_P_H
+
+#include "qsgitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGPaintedItemPrivate : public QSGItemPrivate
+{
+public:
+ QSGPaintedItemPrivate();
+
+ QColor fillColor;
+ QSGPaintedItem::RenderTarget renderTarget;
+
+ QRect dirtyRect;
+
+ bool geometryDirty : 1;
+ bool contentsDirty : 1;
+ bool opaquePainting: 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGPAINTEDITEM_P_P_H
diff --git a/src/declarative/items/qsgpathview.cpp b/src/declarative/items/qsgpathview.cpp
new file mode 100644
index 0000000000..f7dda6cb27
--- /dev/null
+++ b/src/declarative/items/qsgpathview.cpp
@@ -0,0 +1,1410 @@
+// Commit: ac704e9f682378a5ec56e3f5c195dcf2f2dfa1ac
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpathview_p.h"
+#include "qsgpathview_p_p.h"
+#include "qsgcanvas.h"
+
+#include <private/qdeclarativestate_p.h>
+#include <private/qdeclarativeopenmetaobject_p.h>
+#include <private/qlistmodelinterface_p.h>
+
+#include <QtGui/qevent.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/qmath.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+inline qreal qmlMod(qreal x, qreal y)
+{
+#ifdef QT_USE_MATH_H_FLOATS
+ if(sizeof(qreal) == sizeof(float))
+ return fmodf(float(x), float(y));
+ else
+#endif
+ return fmod(x, y);
+}
+
+static QDeclarativeOpenMetaObjectType *qPathViewAttachedType = 0;
+
+QSGPathViewAttached::QSGPathViewAttached(QObject *parent)
+: QObject(parent), m_percent(-1), m_view(0), m_onPath(false), m_isCurrent(false)
+{
+ if (qPathViewAttachedType) {
+ m_metaobject = new QDeclarativeOpenMetaObject(this, qPathViewAttachedType);
+ m_metaobject->setCached(true);
+ } else {
+ m_metaobject = new QDeclarativeOpenMetaObject(this);
+ }
+}
+
+QSGPathViewAttached::~QSGPathViewAttached()
+{
+}
+
+QVariant QSGPathViewAttached::value(const QByteArray &name) const
+{
+ return m_metaobject->value(name);
+}
+void QSGPathViewAttached::setValue(const QByteArray &name, const QVariant &val)
+{
+ m_metaobject->setValue(name, val);
+}
+
+
+void QSGPathViewPrivate::init()
+{
+ Q_Q(QSGPathView);
+ offset = 0;
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QSGItem::ItemIsFocusScope);
+ q->setFiltersChildMouseEvents(true);
+ q->connect(&tl, SIGNAL(updated()), q, SLOT(ticked()));
+ lastPosTime.invalidate();
+ static int timelineCompletedIdx = -1;
+ static int movementEndingIdx = -1;
+ if (timelineCompletedIdx == -1) {
+ timelineCompletedIdx = QDeclarativeTimeLine::staticMetaObject.indexOfSignal("completed()");
+ movementEndingIdx = QSGPathView::staticMetaObject.indexOfSlot("movementEnding()");
+ }
+ QMetaObject::connect(&tl, timelineCompletedIdx,
+ q, movementEndingIdx, Qt::DirectConnection);
+}
+
+QSGItem *QSGPathViewPrivate::getItem(int modelIndex)
+{
+ Q_Q(QSGPathView);
+ requestedIndex = modelIndex;
+ QSGItem *item = model->item(modelIndex, false);
+ if (item) {
+ if (!attType) {
+ // pre-create one metatype to share with all attached objects
+ attType = new QDeclarativeOpenMetaObjectType(&QSGPathViewAttached::staticMetaObject, qmlEngine(q));
+ foreach(const QString &attr, path->attributes())
+ attType->createProperty(attr.toUtf8());
+ }
+ qPathViewAttachedType = attType;
+ QSGPathViewAttached *att = static_cast<QSGPathViewAttached *>(qmlAttachedPropertiesObject<QSGPathView>(item));
+ qPathViewAttachedType = 0;
+ if (att) {
+ att->m_view = q;
+ att->setOnPath(true);
+ }
+ item->setParentItem(q);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ }
+ requestedIndex = -1;
+ return item;
+}
+
+void QSGPathViewPrivate::releaseItem(QSGItem *item)
+{
+ if (!item || !model)
+ return;
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ itemPrivate->removeItemChangeListener(this, QSGItemPrivate::Geometry);
+ if (model->release(item) == 0) {
+ // item was not destroyed, and we no longer reference it.
+ if (QSGPathViewAttached *att = attached(item))
+ att->setOnPath(false);
+ }
+}
+
+QSGPathViewAttached *QSGPathViewPrivate::attached(QSGItem *item)
+{
+ return static_cast<QSGPathViewAttached *>(qmlAttachedPropertiesObject<QSGPathView>(item, false));
+}
+
+void QSGPathViewPrivate::clear()
+{
+ for (int i=0; i<items.count(); i++){
+ QSGItem *p = items[i];
+ releaseItem(p);
+ }
+ items.clear();
+}
+
+void QSGPathViewPrivate::updateMappedRange()
+{
+ if (model && pathItems != -1 && pathItems < modelCount)
+ mappedRange = qreal(pathItems)/modelCount;
+ else
+ mappedRange = 1.0;
+}
+
+qreal QSGPathViewPrivate::positionOfIndex(qreal index) const
+{
+ qreal pos = -1.0;
+
+ if (model && index >= 0 && index < modelCount) {
+ qreal start = 0.0;
+ if (haveHighlightRange && highlightRangeMode != QSGPathView::NoHighlightRange)
+ start = highlightRangeStart;
+ qreal globalPos = index + offset;
+ globalPos = qmlMod(globalPos, qreal(modelCount)) / modelCount;
+ if (pathItems != -1 && pathItems < modelCount) {
+ globalPos += start * mappedRange;
+ globalPos = qmlMod(globalPos, 1.0);
+ if (globalPos < mappedRange)
+ pos = globalPos / mappedRange;
+ } else {
+ pos = qmlMod(globalPos + start, 1.0);
+ }
+ }
+
+ return pos;
+}
+
+void QSGPathViewPrivate::createHighlight()
+{
+ Q_Q(QSGPathView);
+ if (!q->isComponentComplete())
+ return;
+
+ bool changed = false;
+ if (highlightItem) {
+ delete highlightItem;
+ highlightItem = 0;
+ changed = true;
+ }
+
+ QSGItem *item = 0;
+ if (highlightComponent) {
+ QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = highlightComponent->create(highlightContext);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(highlightContext, nobj);
+ item = qobject_cast<QSGItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete highlightContext;
+ }
+ } else {
+ item = new QSGItem;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q);
+ item->setParentItem(q);
+ highlightItem = item;
+ changed = true;
+ }
+ if (changed)
+ emit q->highlightItemChanged();
+}
+
+void QSGPathViewPrivate::updateHighlight()
+{
+ Q_Q(QSGPathView);
+ if (!q->isComponentComplete() || !isValid())
+ return;
+ if (highlightItem) {
+ if (haveHighlightRange && highlightRangeMode == QSGPathView::StrictlyEnforceRange) {
+ updateItem(highlightItem, highlightRangeStart);
+ } else {
+ qreal target = currentIndex;
+
+ offsetAdj = 0.0;
+ tl.reset(moveHighlight);
+ moveHighlight.setValue(highlightPosition);
+
+ const int duration = highlightMoveDuration;
+
+ if (target - highlightPosition > modelCount/2) {
+ highlightUp = false;
+ qreal distance = modelCount - target + highlightPosition;
+ tl.move(moveHighlight, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * highlightPosition / distance));
+ tl.set(moveHighlight, modelCount-0.01);
+ tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad), int(duration * (modelCount-target) / distance));
+ } else if (target - highlightPosition <= -modelCount/2) {
+ highlightUp = true;
+ qreal distance = modelCount - highlightPosition + target;
+ tl.move(moveHighlight, modelCount-0.01, QEasingCurve(QEasingCurve::InQuad), int(duration * (modelCount-highlightPosition) / distance));
+ tl.set(moveHighlight, 0.0);
+ tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad), int(duration * target / distance));
+ } else {
+ highlightUp = highlightPosition - target < 0;
+ tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::InOutQuad), duration);
+ }
+ }
+ }
+}
+
+void QSGPathViewPrivate::setHighlightPosition(qreal pos)
+{
+ if (pos != highlightPosition) {
+ qreal start = 0.0;
+ qreal end = 1.0;
+ if (haveHighlightRange && highlightRangeMode != QSGPathView::NoHighlightRange) {
+ start = highlightRangeStart;
+ end = highlightRangeEnd;
+ }
+
+ qreal range = qreal(modelCount);
+ // calc normalized position of highlight relative to offset
+ qreal relativeHighlight = qmlMod(pos + offset, range) / range;
+
+ if (!highlightUp && relativeHighlight > end * mappedRange) {
+ qreal diff = 1.0 - relativeHighlight;
+ setOffset(offset + diff * range);
+ } else if (highlightUp && relativeHighlight >= (end - start) * mappedRange) {
+ qreal diff = relativeHighlight - (end - start) * mappedRange;
+ setOffset(offset - diff * range - 0.00001);
+ }
+
+ highlightPosition = pos;
+ qreal pathPos = positionOfIndex(pos);
+ updateItem(highlightItem, pathPos);
+ if (QSGPathViewAttached *att = attached(highlightItem))
+ att->setOnPath(pathPos != -1.0);
+ }
+}
+
+void QSGPathView::pathUpdated()
+{
+ Q_D(QSGPathView);
+ QList<QSGItem*>::iterator it = d->items.begin();
+ while (it != d->items.end()) {
+ QSGItem *item = *it;
+ if (QSGPathViewAttached *att = d->attached(item))
+ att->m_percent = -1;
+ ++it;
+ }
+ refill();
+}
+
+void QSGPathViewPrivate::updateItem(QSGItem *item, qreal percent)
+{
+ if (QSGPathViewAttached *att = attached(item)) {
+ if (qFuzzyCompare(att->m_percent, percent))
+ return;
+ att->m_percent = percent;
+ foreach(const QString &attr, path->attributes())
+ att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
+ }
+ QPointF pf = path->pointAt(percent);
+ item->setX(qRound(pf.x() - item->width()/2));
+ item->setY(qRound(pf.y() - item->height()/2));
+}
+
+void QSGPathViewPrivate::regenerate()
+{
+ Q_Q(QSGPathView);
+ if (!q->isComponentComplete())
+ return;
+
+ clear();
+
+ if (!isValid())
+ return;
+
+ firstIndex = -1;
+ updateMappedRange();
+ q->refill();
+}
+
+QSGPathView::QSGPathView(QSGItem *parent)
+ : QSGItem(*(new QSGPathViewPrivate), parent)
+{
+ Q_D(QSGPathView);
+ d->init();
+}
+
+QSGPathView::~QSGPathView()
+{
+ Q_D(QSGPathView);
+ d->clear();
+ if (d->attType)
+ d->attType->release();
+ if (d->ownModel)
+ delete d->model;
+}
+
+QVariant QSGPathView::model() const
+{
+ Q_D(const QSGPathView);
+ return d->modelVariant;
+}
+
+void QSGPathView::setModel(const QVariant &model)
+{
+ Q_D(QSGPathView);
+ if (d->modelVariant == model)
+ return;
+
+ if (d->model) {
+ disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ for (int i=0; i<d->items.count(); i++){
+ QSGItem *p = d->items[i];
+ d->model->release(p);
+ }
+ d->items.clear();
+ }
+
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QSGVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QSGVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this), this);
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ dataModel->setModel(model);
+ }
+ d->modelCount = 0;
+ if (d->model) {
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ d->modelCount = d->model->count();
+ if (d->model->count())
+ d->offset = qmlMod(d->offset, qreal(d->model->count()));
+ if (d->offset < 0)
+ d->offset = d->model->count() + d->offset;
+}
+ d->regenerate();
+ d->fixOffset();
+ emit countChanged();
+ emit modelChanged();
+}
+
+int QSGPathView::count() const
+{
+ Q_D(const QSGPathView);
+ return d->model ? d->modelCount : 0;
+}
+
+QDeclarativePath *QSGPathView::path() const
+{
+ Q_D(const QSGPathView);
+ return d->path;
+}
+
+void QSGPathView::setPath(QDeclarativePath *path)
+{
+ Q_D(QSGPathView);
+ if (d->path == path)
+ return;
+ if (d->path)
+ disconnect(d->path, SIGNAL(changed()), this, SLOT(pathUpdated()));
+ d->path = path;
+ connect(d->path, SIGNAL(changed()), this, SLOT(pathUpdated()));
+ if (d->isValid() && isComponentComplete()) {
+ d->clear();
+ if (d->attType) {
+ d->attType->release();
+ d->attType = 0;
+ }
+ d->regenerate();
+ }
+ emit pathChanged();
+}
+
+int QSGPathView::currentIndex() const
+{
+ Q_D(const QSGPathView);
+ return d->currentIndex;
+}
+
+void QSGPathView::setCurrentIndex(int idx)
+{
+ Q_D(QSGPathView);
+ if (d->model && d->modelCount)
+ idx = qAbs(idx % d->modelCount);
+ if (d->model && idx != d->currentIndex) {
+ if (d->modelCount) {
+ int itemIndex = (d->currentIndex - d->firstIndex + d->modelCount) % d->modelCount;
+ if (itemIndex < d->items.count()) {
+ if (QSGItem *item = d->items.at(itemIndex)) {
+ if (QSGPathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(false);
+ }
+ }
+ }
+ d->currentItem = 0;
+ d->moveReason = QSGPathViewPrivate::SetIndex;
+ d->currentIndex = idx;
+ if (d->modelCount) {
+ if (d->haveHighlightRange && d->highlightRangeMode == QSGPathView::StrictlyEnforceRange)
+ d->snapToCurrent();
+ int itemIndex = (idx - d->firstIndex + d->modelCount) % d->modelCount;
+ if (itemIndex < d->items.count()) {
+ d->currentItem = d->items.at(itemIndex);
+ d->currentItem->setFocus(true);
+ if (QSGPathViewAttached *att = d->attached(d->currentItem))
+ att->setIsCurrentItem(true);
+ }
+ d->currentItemOffset = d->positionOfIndex(d->currentIndex);
+ d->updateHighlight();
+ }
+ emit currentIndexChanged();
+ }
+}
+
+void QSGPathView::incrementCurrentIndex()
+{
+ Q_D(QSGPathView);
+ d->moveDirection = QSGPathViewPrivate::Positive;
+ setCurrentIndex(currentIndex()+1);
+}
+
+void QSGPathView::decrementCurrentIndex()
+{
+ Q_D(QSGPathView);
+ if (d->model && d->modelCount) {
+ int idx = currentIndex()-1;
+ if (idx < 0)
+ idx = d->modelCount - 1;
+ d->moveDirection = QSGPathViewPrivate::Negative;
+ setCurrentIndex(idx);
+ }
+}
+
+qreal QSGPathView::offset() const
+{
+ Q_D(const QSGPathView);
+ return d->offset;
+}
+
+void QSGPathView::setOffset(qreal offset)
+{
+ Q_D(QSGPathView);
+ d->setOffset(offset);
+ d->updateCurrent();
+}
+
+void QSGPathViewPrivate::setOffset(qreal o)
+{
+ Q_Q(QSGPathView);
+ if (offset != o) {
+ if (isValid() && q->isComponentComplete()) {
+ offset = qmlMod(o, qreal(modelCount));
+ if (offset < 0)
+ offset += qreal(modelCount);
+ q->refill();
+ } else {
+ offset = o;
+ }
+ emit q->offsetChanged();
+ }
+}
+
+void QSGPathViewPrivate::setAdjustedOffset(qreal o)
+{
+ setOffset(o+offsetAdj);
+}
+
+QDeclarativeComponent *QSGPathView::highlight() const
+{
+ Q_D(const QSGPathView);
+ return d->highlightComponent;
+}
+
+void QSGPathView::setHighlight(QDeclarativeComponent *highlight)
+{
+ Q_D(QSGPathView);
+ if (highlight != d->highlightComponent) {
+ d->highlightComponent = highlight;
+ d->createHighlight();
+ d->updateHighlight();
+ emit highlightChanged();
+ }
+}
+
+QSGItem *QSGPathView::highlightItem()
+{
+ Q_D(const QSGPathView);
+ return d->highlightItem;
+}
+
+qreal QSGPathView::preferredHighlightBegin() const
+{
+ Q_D(const QSGPathView);
+ return d->highlightRangeStart;
+}
+
+void QSGPathView::setPreferredHighlightBegin(qreal start)
+{
+ Q_D(QSGPathView);
+ if (d->highlightRangeStart == start || start < 0 || start > 1.0)
+ return;
+ d->highlightRangeStart = start;
+ d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ refill();
+ emit preferredHighlightBeginChanged();
+}
+
+qreal QSGPathView::preferredHighlightEnd() const
+{
+ Q_D(const QSGPathView);
+ return d->highlightRangeEnd;
+}
+
+void QSGPathView::setPreferredHighlightEnd(qreal end)
+{
+ Q_D(QSGPathView);
+ if (d->highlightRangeEnd == end || end < 0 || end > 1.0)
+ return;
+ d->highlightRangeEnd = end;
+ d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ refill();
+ emit preferredHighlightEndChanged();
+}
+
+QSGPathView::HighlightRangeMode QSGPathView::highlightRangeMode() const
+{
+ Q_D(const QSGPathView);
+ return d->highlightRangeMode;
+}
+
+void QSGPathView::setHighlightRangeMode(HighlightRangeMode mode)
+{
+ Q_D(QSGPathView);
+ if (d->highlightRangeMode == mode)
+ return;
+ d->highlightRangeMode = mode;
+ d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit highlightRangeModeChanged();
+}
+
+int QSGPathView::highlightMoveDuration() const
+{
+ Q_D(const QSGPathView);
+ return d->highlightMoveDuration;
+}
+
+void QSGPathView::setHighlightMoveDuration(int duration)
+{
+ Q_D(QSGPathView);
+ if (d->highlightMoveDuration == duration)
+ return;
+ d->highlightMoveDuration = duration;
+ emit highlightMoveDurationChanged();
+}
+
+qreal QSGPathView::dragMargin() const
+{
+ Q_D(const QSGPathView);
+ return d->dragMargin;
+}
+
+void QSGPathView::setDragMargin(qreal dragMargin)
+{
+ Q_D(QSGPathView);
+ if (d->dragMargin == dragMargin)
+ return;
+ d->dragMargin = dragMargin;
+ emit dragMarginChanged();
+}
+
+qreal QSGPathView::flickDeceleration() const
+{
+ Q_D(const QSGPathView);
+ return d->deceleration;
+}
+
+void QSGPathView::setFlickDeceleration(qreal dec)
+{
+ Q_D(QSGPathView);
+ if (d->deceleration == dec)
+ return;
+ d->deceleration = dec;
+ emit flickDecelerationChanged();
+}
+
+bool QSGPathView::isInteractive() const
+{
+ Q_D(const QSGPathView);
+ return d->interactive;
+}
+
+void QSGPathView::setInteractive(bool interactive)
+{
+ Q_D(QSGPathView);
+ if (interactive != d->interactive) {
+ d->interactive = interactive;
+ if (!interactive)
+ d->tl.clear();
+ emit interactiveChanged();
+ }
+}
+
+bool QSGPathView::isMoving() const
+{
+ Q_D(const QSGPathView);
+ return d->moving;
+}
+
+bool QSGPathView::isFlicking() const
+{
+ Q_D(const QSGPathView);
+ return d->flicking;
+}
+
+QDeclarativeComponent *QSGPathView::delegate() const
+{
+ Q_D(const QSGPathView);
+ if (d->model) {
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QSGPathView::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QSGPathView);
+ if (delegate == this->delegate())
+ return;
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model)) {
+ dataModel->setDelegate(delegate);
+ d->modelCount = dataModel->count();
+ d->regenerate();
+ emit delegateChanged();
+ }
+}
+
+int QSGPathView::pathItemCount() const
+{
+ Q_D(const QSGPathView);
+ return d->pathItems;
+}
+
+void QSGPathView::setPathItemCount(int i)
+{
+ Q_D(QSGPathView);
+ if (i == d->pathItems)
+ return;
+ if (i < 1)
+ i = 1;
+ d->pathItems = i;
+ d->updateMappedRange();
+ if (d->isValid() && isComponentComplete()) {
+ d->regenerate();
+ }
+ emit pathItemCountChanged();
+}
+
+QPointF QSGPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const
+{
+ //XXX maybe do recursively at increasing resolution.
+ qreal mindist = 1e10; // big number
+ QPointF nearPoint = path->pointAt(0);
+ qreal nearPc = 0;
+ for (qreal i=1; i < 1000; i++) {
+ QPointF pt = path->pointAt(i/1000.0);
+ QPointF diff = pt - point;
+ qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
+ if (dist < mindist) {
+ nearPoint = pt;
+ nearPc = i;
+ mindist = dist;
+ }
+ }
+
+ if (nearPercent)
+ *nearPercent = nearPc / 1000.0;
+
+ return nearPoint;
+}
+
+void QSGPathView::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPathView);
+ if (d->interactive) {
+ d->handleMousePressEvent(event);
+ event->accept();
+ } else {
+ QSGItem::mousePressEvent(event);
+ }
+}
+
+void QSGPathViewPrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGPathView);
+ if (!interactive || !items.count())
+ return;
+ QPointF scenePoint = q->mapToScene(event->pos());
+ int idx = 0;
+ for (; idx < items.count(); ++idx) {
+ QRectF rect = items.at(idx)->boundingRect();
+ rect = items.at(idx)->mapRectToScene(rect);
+ if (rect.contains(scenePoint))
+ break;
+ }
+ if (idx == items.count() && dragMargin == 0.) // didn't click on an item
+ return;
+
+ startPoint = pointNear(event->pos(), &startPc);
+ if (idx == items.count()) {
+ qreal distance = qAbs(event->pos().x() - startPoint.x()) + qAbs(event->pos().y() - startPoint.y());
+ if (distance > dragMargin)
+ return;
+ }
+
+ if (tl.isActive() && flicking)
+ stealMouse = true; // If we've been flicked then steal the click.
+ else
+ stealMouse = false;
+
+ lastElapsed = 0;
+ lastDist = 0;
+ QSGItemPrivate::start(lastPosTime);
+ tl.clear();
+}
+
+void QSGPathView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPathView);
+ if (d->interactive) {
+ d->handleMouseMoveEvent(event);
+ if (d->stealMouse)
+ setKeepMouseGrab(true);
+ event->accept();
+ } else {
+ QSGItem::mouseMoveEvent(event);
+ }
+}
+
+void QSGPathViewPrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QSGPathView);
+ if (!interactive || !lastPosTime.isValid())
+ return;
+
+ qreal newPc;
+ QPointF pathPoint = pointNear(event->pos(), &newPc);
+ if (!stealMouse) {
+ QPointF delta = pathPoint - startPoint;
+ if (qAbs(delta.x()) > QApplication::startDragDistance() || qAbs(delta.y()) > QApplication::startDragDistance()) {
+ stealMouse = true;
+ startPc = newPc;
+ }
+ }
+
+ if (stealMouse) {
+ moveReason = QSGPathViewPrivate::Mouse;
+ qreal diff = (newPc - startPc)*modelCount*mappedRange;
+ if (diff) {
+ q->setOffset(offset + diff);
+
+ if (diff > modelCount/2)
+ diff -= modelCount;
+ else if (diff < -modelCount/2)
+ diff += modelCount;
+
+ lastElapsed = QSGItemPrivate::restart(lastPosTime);
+ lastDist = diff;
+ startPc = newPc;
+ }
+ if (!moving) {
+ moving = true;
+ emit q->movingChanged();
+ emit q->movementStarted();
+ }
+ }
+}
+
+void QSGPathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPathView);
+ if (d->interactive) {
+ d->handleMouseReleaseEvent(event);
+ event->accept();
+ ungrabMouse();
+ } else {
+ QSGItem::mouseReleaseEvent(event);
+ }
+}
+
+void QSGPathViewPrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *)
+{
+ Q_Q(QSGPathView);
+ stealMouse = false;
+ q->setKeepMouseGrab(false);
+ if (!interactive || !lastPosTime.isValid())
+ return;
+
+ qreal elapsed = qreal(lastElapsed + QSGItemPrivate::elapsed(lastPosTime)) / 1000.;
+ qreal velocity = elapsed > 0. ? lastDist / elapsed : 0;
+ if (model && modelCount && qAbs(velocity) > 1.) {
+ qreal count = pathItems == -1 ? modelCount : pathItems;
+ if (qAbs(velocity) > count * 2) // limit velocity
+ velocity = (velocity > 0 ? count : -count) * 2;
+ // Calculate the distance to be travelled
+ qreal v2 = velocity*velocity;
+ qreal accel = deceleration/10;
+ // + 0.25 to encourage moving at least one item in the flick direction
+ qreal dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2.0) + 0.25));
+ if (haveHighlightRange && highlightRangeMode == QSGPathView::StrictlyEnforceRange) {
+ // round to nearest item.
+ if (velocity > 0.)
+ dist = qRound(dist + offset) - offset;
+ else
+ dist = qRound(dist - offset) + offset;
+ // Calculate accel required to stop on item boundary
+ if (dist <= 0.) {
+ dist = 0.;
+ accel = 0.;
+ } else {
+ accel = v2 / (2.0f * qAbs(dist));
+ }
+ }
+ offsetAdj = 0.0;
+ moveOffset.setValue(offset);
+ tl.accel(moveOffset, velocity, accel, dist);
+ tl.callback(QDeclarativeTimeLineCallback(&moveOffset, fixOffsetCallback, this));
+ if (!flicking) {
+ flicking = true;
+ emit q->flickingChanged();
+ emit q->flickStarted();
+ }
+ } else {
+ fixOffset();
+ }
+
+ lastPosTime.invalidate();
+ if (!tl.isActive())
+ q->movementEnding();
+}
+
+bool QSGPathView::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPathView);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+ QSGCanvas *c = canvas();
+ QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ d->handleMouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ d->handleMousePressEvent(&mouseEvent);
+ stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ d->handleMouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = c->mouseGrabberItem();
+ if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ return d->stealMouse;
+ } else if (d->lastPosTime.isValid()) {
+ d->lastPosTime.invalidate();
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease)
+ d->stealMouse = false;
+ return false;
+}
+
+bool QSGPathView::childMouseEventFilter(QSGItem *i, QEvent *e)
+{
+ Q_D(QSGPathView);
+ if (!isVisible() || !d->interactive)
+ return QSGItem::childMouseEventFilter(i, e);
+
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ default:
+ break;
+ }
+
+ return QSGItem::childMouseEventFilter(i, e);
+}
+
+void QSGPathView::updatePolish()
+{
+ QSGItem::updatePolish();
+ refill();
+}
+
+void QSGPathView::componentComplete()
+{
+ Q_D(QSGPathView);
+ QSGItem::componentComplete();
+ d->createHighlight();
+ // It is possible that a refill has already happended to to Path
+ // bindings being handled in the componentComplete(). If so
+ // don't do it again.
+ if (d->items.count() == 0 && d->model) {
+ d->modelCount = d->model->count();
+ d->regenerate();
+ }
+ d->updateHighlight();
+}
+
+void QSGPathView::refill()
+{
+ Q_D(QSGPathView);
+ if (!d->isValid() || !isComponentComplete())
+ return;
+
+ d->layoutScheduled = false;
+ bool currentVisible = false;
+
+ // first move existing items and remove items off path
+ int idx = d->firstIndex;
+ QList<QSGItem*>::iterator it = d->items.begin();
+ while (it != d->items.end()) {
+ qreal pos = d->positionOfIndex(idx);
+ QSGItem *item = *it;
+ if (pos >= 0.0) {
+ d->updateItem(item, pos);
+ if (idx == d->currentIndex) {
+ currentVisible = true;
+ d->currentItemOffset = pos;
+ }
+ ++it;
+ } else {
+// qDebug() << "release";
+ d->updateItem(item, 1.0);
+ d->releaseItem(item);
+ if (it == d->items.begin()) {
+ if (++d->firstIndex >= d->modelCount)
+ d->firstIndex = 0;
+ }
+ it = d->items.erase(it);
+ }
+ ++idx;
+ if (idx >= d->modelCount)
+ idx = 0;
+ }
+ if (!d->items.count())
+ d->firstIndex = -1;
+
+ if (d->modelCount) {
+ // add items to beginning and end
+ int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount);
+ if (d->items.count() < count) {
+ int idx = qRound(d->modelCount - d->offset) % d->modelCount;
+ qreal startPos = 0.0;
+ if (d->haveHighlightRange && d->highlightRangeMode != QSGPathView::NoHighlightRange)
+ startPos = d->highlightRangeStart;
+ if (d->firstIndex >= 0) {
+ startPos = d->positionOfIndex(d->firstIndex);
+ idx = (d->firstIndex + d->items.count()) % d->modelCount;
+ }
+ qreal pos = d->positionOfIndex(idx);
+ while ((pos > startPos || !d->items.count()) && d->items.count() < count) {
+ // qDebug() << "append" << idx;
+ QSGItem *item = d->getItem(idx);
+ if (d->model->completePending())
+ item->setZ(idx+1);
+ if (d->currentIndex == idx) {
+ item->setFocus(true);
+ if (QSGPathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(true);
+ currentVisible = true;
+ d->currentItemOffset = pos;
+ d->currentItem = item;
+ }
+ if (d->items.count() == 0)
+ d->firstIndex = idx;
+ d->items.append(item);
+ d->updateItem(item, pos);
+ if (d->model->completePending())
+ d->model->completeItem();
+ ++idx;
+ if (idx >= d->modelCount)
+ idx = 0;
+ pos = d->positionOfIndex(idx);
+ }
+
+ idx = d->firstIndex - 1;
+ if (idx < 0)
+ idx = d->modelCount - 1;
+ pos = d->positionOfIndex(idx);
+ while (pos >= 0.0 && pos < startPos) {
+ // qDebug() << "prepend" << idx;
+ QSGItem *item = d->getItem(idx);
+ if (d->model->completePending())
+ item->setZ(idx+1);
+ if (d->currentIndex == idx) {
+ item->setFocus(true);
+ if (QSGPathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(true);
+ currentVisible = true;
+ d->currentItemOffset = pos;
+ d->currentItem = item;
+ }
+ d->items.prepend(item);
+ d->updateItem(item, pos);
+ if (d->model->completePending())
+ d->model->completeItem();
+ d->firstIndex = idx;
+ idx = d->firstIndex - 1;
+ if (idx < 0)
+ idx = d->modelCount - 1;
+ pos = d->positionOfIndex(idx);
+ }
+ }
+ }
+
+ if (!currentVisible)
+ d->currentItemOffset = 1.0;
+
+ if (d->highlightItem && d->haveHighlightRange && d->highlightRangeMode == QSGPathView::StrictlyEnforceRange) {
+ d->updateItem(d->highlightItem, d->highlightRangeStart);
+ if (QSGPathViewAttached *att = d->attached(d->highlightItem))
+ att->setOnPath(true);
+ } else if (d->highlightItem && d->moveReason != QSGPathViewPrivate::SetIndex) {
+ d->updateItem(d->highlightItem, d->currentItemOffset);
+ if (QSGPathViewAttached *att = d->attached(d->highlightItem))
+ att->setOnPath(currentVisible);
+ }
+ while (d->itemCache.count())
+ d->releaseItem(d->itemCache.takeLast());
+}
+
+void QSGPathView::itemsInserted(int modelIndex, int count)
+{
+ //XXX support animated insertion
+ Q_D(QSGPathView);
+ if (!d->isValid() || !isComponentComplete())
+ return;
+
+ if (d->modelCount) {
+ d->itemCache += d->items;
+ d->items.clear();
+ if (modelIndex <= d->currentIndex) {
+ d->currentIndex += count;
+ emit currentIndexChanged();
+ } else if (d->offset != 0) {
+ d->offset += count;
+ d->offsetAdj += count;
+ }
+ }
+
+ d->modelCount += count;
+ if (d->flicking || d->moving) {
+ d->regenerate();
+ d->updateCurrent();
+ } else {
+ d->firstIndex = -1;
+ d->updateMappedRange();
+ d->scheduleLayout();
+ }
+ emit countChanged();
+}
+
+void QSGPathView::itemsRemoved(int modelIndex, int count)
+{
+ //XXX support animated removal
+ Q_D(QSGPathView);
+ if (!d->model || !d->modelCount || !d->model->isValid() || !d->path || !isComponentComplete())
+ return;
+
+ // fix current
+ bool currentChanged = false;
+ if (d->currentIndex >= modelIndex + count) {
+ d->currentIndex -= count;
+ currentChanged = true;
+ } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
+ // current item has been removed.
+ d->currentIndex = qMin(modelIndex, d->modelCount-count-1);
+ if (d->currentItem) {
+ if (QSGPathViewAttached *att = d->attached(d->currentItem))
+ att->setIsCurrentItem(true);
+ }
+ currentChanged = true;
+ }
+
+ d->itemCache += d->items;
+ d->items.clear();
+
+ bool changedOffset = false;
+ if (modelIndex > d->currentIndex) {
+ if (d->offset >= count) {
+ changedOffset = true;
+ d->offset -= count;
+ d->offsetAdj -= count;
+ }
+ }
+
+ d->modelCount -= count;
+ if (!d->modelCount) {
+ while (d->itemCache.count())
+ d->releaseItem(d->itemCache.takeLast());
+ d->offset = 0;
+ changedOffset = true;
+ d->tl.reset(d->moveOffset);
+ } else {
+ d->regenerate();
+ d->updateCurrent();
+ }
+ if (changedOffset)
+ emit offsetChanged();
+ if (currentChanged)
+ emit currentIndexChanged();
+ emit countChanged();
+}
+
+void QSGPathView::itemsMoved(int /*from*/, int /*to*/, int /*count*/)
+{
+ Q_D(QSGPathView);
+ if (!d->isValid() || !isComponentComplete())
+ return;
+
+ QList<QSGItem *> removedItems = d->items;
+ d->items.clear();
+ d->regenerate();
+ while (removedItems.count())
+ d->releaseItem(removedItems.takeLast());
+
+ // Fix current index
+ if (d->currentIndex >= 0 && d->currentItem) {
+ int oldCurrent = d->currentIndex;
+ d->currentIndex = d->model->indexOf(d->currentItem, this);
+ if (oldCurrent != d->currentIndex)
+ emit currentIndexChanged();
+ }
+ d->updateCurrent();
+}
+
+void QSGPathView::modelReset()
+{
+ Q_D(QSGPathView);
+ d->modelCount = d->model->count();
+ d->regenerate();
+ emit countChanged();
+}
+
+void QSGPathView::createdItem(int index, QSGItem *item)
+{
+ Q_D(QSGPathView);
+ if (d->requestedIndex != index) {
+ if (!d->attType) {
+ // pre-create one metatype to share with all attached objects
+ d->attType = new QDeclarativeOpenMetaObjectType(&QSGPathViewAttached::staticMetaObject, qmlEngine(this));
+ foreach(const QString &attr, d->path->attributes())
+ d->attType->createProperty(attr.toUtf8());
+ }
+ qPathViewAttachedType = d->attType;
+ QSGPathViewAttached *att = static_cast<QSGPathViewAttached *>(qmlAttachedPropertiesObject<QSGPathView>(item));
+ qPathViewAttachedType = 0;
+ if (att) {
+ att->m_view = this;
+ att->setOnPath(false);
+ }
+ item->setParentItem(this);
+ d->updateItem(item, index < d->firstIndex ? 0.0 : 1.0);
+ }
+}
+
+void QSGPathView::destroyingItem(QSGItem *item)
+{
+ Q_UNUSED(item);
+}
+
+void QSGPathView::ticked()
+{
+ Q_D(QSGPathView);
+ d->updateCurrent();
+}
+
+void QSGPathView::movementEnding()
+{
+ Q_D(QSGPathView);
+ if (d->flicking) {
+ d->flicking = false;
+ emit flickingChanged();
+ emit flickEnded();
+ }
+ if (d->moving && !d->stealMouse) {
+ d->moving = false;
+ emit movingChanged();
+ emit movementEnded();
+ }
+}
+
+// find the item closest to the snap position
+int QSGPathViewPrivate::calcCurrentIndex()
+{
+ int current = -1;
+ if (modelCount && model && items.count()) {
+ offset = qmlMod(offset, modelCount);
+ if (offset < 0)
+ offset += modelCount;
+ current = qRound(qAbs(qmlMod(modelCount - offset, modelCount)));
+ current = current % modelCount;
+ }
+
+ return current;
+}
+
+void QSGPathViewPrivate::updateCurrent()
+{
+ Q_Q(QSGPathView);
+ if (moveReason != Mouse)
+ return;
+ if (!modelCount || !haveHighlightRange || highlightRangeMode != QSGPathView::StrictlyEnforceRange)
+ return;
+
+ int idx = calcCurrentIndex();
+ if (model && idx != currentIndex) {
+ int itemIndex = (currentIndex - firstIndex + modelCount) % modelCount;
+ if (itemIndex < items.count()) {
+ if (QSGItem *item = items.at(itemIndex)) {
+ if (QSGPathViewAttached *att = attached(item))
+ att->setIsCurrentItem(false);
+ }
+ }
+ currentIndex = idx;
+ currentItem = 0;
+ itemIndex = (idx - firstIndex + modelCount) % modelCount;
+ if (itemIndex < items.count()) {
+ currentItem = items.at(itemIndex);
+ currentItem->setFocus(true);
+ if (QSGPathViewAttached *att = attached(currentItem))
+ att->setIsCurrentItem(true);
+ }
+ emit q->currentIndexChanged();
+ }
+}
+
+void QSGPathViewPrivate::fixOffsetCallback(void *d)
+{
+ ((QSGPathViewPrivate *)d)->fixOffset();
+}
+
+void QSGPathViewPrivate::fixOffset()
+{
+ Q_Q(QSGPathView);
+ if (model && items.count()) {
+ if (haveHighlightRange && highlightRangeMode == QSGPathView::StrictlyEnforceRange) {
+ int curr = calcCurrentIndex();
+ if (curr != currentIndex)
+ q->setCurrentIndex(curr);
+ else
+ snapToCurrent();
+ }
+ }
+}
+
+void QSGPathViewPrivate::snapToCurrent()
+{
+ if (!model || modelCount <= 0)
+ return;
+
+ qreal targetOffset = qmlMod(modelCount - currentIndex, modelCount);
+
+ moveReason = Other;
+ offsetAdj = 0.0;
+ tl.reset(moveOffset);
+ moveOffset.setValue(offset);
+
+ const int duration = highlightMoveDuration;
+
+ if (moveDirection == Positive || (moveDirection == Shortest && targetOffset - offset > modelCount/2)) {
+ qreal distance = modelCount - targetOffset + offset;
+ if (targetOffset > moveOffset) {
+ tl.move(moveOffset, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * offset / distance));
+ tl.set(moveOffset, modelCount);
+ tl.move(moveOffset, targetOffset, QEasingCurve(offset == 0.0 ? QEasingCurve::InOutQuad : QEasingCurve::OutQuad), int(duration * (modelCount-targetOffset) / distance));
+ } else {
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
+ }
+ } else if (moveDirection == Negative || targetOffset - offset <= -modelCount/2) {
+ qreal distance = modelCount - offset + targetOffset;
+ if (targetOffset < moveOffset) {
+ tl.move(moveOffset, modelCount, QEasingCurve(targetOffset == 0 ? QEasingCurve::InOutQuad : QEasingCurve::InQuad), int(duration * (modelCount-offset) / distance));
+ tl.set(moveOffset, 0.0);
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::OutQuad), int(duration * targetOffset / distance));
+ } else {
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
+ }
+ } else {
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
+ }
+ moveDirection = Shortest;
+}
+
+QSGPathViewAttached *QSGPathView::qmlAttachedProperties(QObject *obj)
+{
+ return new QSGPathViewAttached(obj);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/items/qsgpathview_p.h b/src/declarative/items/qsgpathview_p.h
new file mode 100644
index 0000000000..d75063395a
--- /dev/null
+++ b/src/declarative/items/qsgpathview_p.h
@@ -0,0 +1,254 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPATHVIEW_P_H
+#define QSGPATHVIEW_P_H
+
+#include "qsgitem.h"
+
+#include <private/qdeclarativepath_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGPathViewPrivate;
+class QSGPathViewAttached;
+class Q_AUTOTEST_EXPORT QSGPathView : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativePath *path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+ Q_PROPERTY(qreal offset READ offset WRITE setOffset NOTIFY offsetChanged)
+
+ Q_PROPERTY(QDeclarativeComponent *highlight READ highlight WRITE setHighlight NOTIFY highlightChanged)
+ Q_PROPERTY(QSGItem *highlightItem READ highlightItem NOTIFY highlightItemChanged)
+
+ Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged)
+ Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged)
+ Q_PROPERTY(HighlightRangeMode highlightRangeMode READ highlightRangeMode WRITE setHighlightRangeMode NOTIFY highlightRangeModeChanged)
+ Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged)
+
+ Q_PROPERTY(qreal dragMargin READ dragMargin WRITE setDragMargin NOTIFY dragMarginChanged)
+ Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
+ Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged)
+
+ Q_PROPERTY(bool moving READ isMoving NOTIFY movingChanged)
+ Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged)
+
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int pathItemCount READ pathItemCount WRITE setPathItemCount NOTIFY pathItemCountChanged)
+
+ Q_ENUMS(HighlightRangeMode)
+
+public:
+ QSGPathView(QSGItem *parent=0);
+ virtual ~QSGPathView();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativePath *path() const;
+ void setPath(QDeclarativePath *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ qreal offset() const;
+ void setOffset(qreal offset);
+
+ QDeclarativeComponent *highlight() const;
+ void setHighlight(QDeclarativeComponent *highlight);
+ QSGItem *highlightItem();
+
+ enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange };
+ HighlightRangeMode highlightRangeMode() const;
+ void setHighlightRangeMode(HighlightRangeMode mode);
+
+ qreal preferredHighlightBegin() const;
+ void setPreferredHighlightBegin(qreal);
+
+ qreal preferredHighlightEnd() const;
+ void setPreferredHighlightEnd(qreal);
+
+ int highlightMoveDuration() const;
+ void setHighlightMoveDuration(int);
+
+ qreal dragMargin() const;
+ void setDragMargin(qreal margin);
+
+ qreal flickDeceleration() const;
+ void setFlickDeceleration(qreal dec);
+
+ bool isInteractive() const;
+ void setInteractive(bool);
+
+ bool isMoving() const;
+ bool isFlicking() const;
+
+ int count() const;
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int pathItemCount() const;
+ void setPathItemCount(int);
+
+ static QSGPathViewAttached *qmlAttachedProperties(QObject *);
+
+public Q_SLOTS:
+ void incrementCurrentIndex();
+ void decrementCurrentIndex();
+
+Q_SIGNALS:
+ void currentIndexChanged();
+ void offsetChanged();
+ void modelChanged();
+ void countChanged();
+ void pathChanged();
+ void preferredHighlightBeginChanged();
+ void preferredHighlightEndChanged();
+ void highlightRangeModeChanged();
+ void dragMarginChanged();
+ void snapPositionChanged();
+ void delegateChanged();
+ void pathItemCountChanged();
+ void flickDecelerationChanged();
+ void interactiveChanged();
+ void movingChanged();
+ void flickingChanged();
+ void highlightChanged();
+ void highlightItemChanged();
+ void highlightMoveDurationChanged();
+ void movementStarted();
+ void movementEnded();
+ void flickStarted();
+ void flickEnded();
+
+protected:
+ virtual void updatePolish();
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+ bool childMouseEventFilter(QSGItem *, QEvent *);
+ void componentComplete();
+
+private Q_SLOTS:
+ void refill();
+ void ticked();
+ void movementEnding();
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int,int,int);
+ void modelReset();
+ void createdItem(int index, QSGItem *item);
+ void destroyingItem(QSGItem *item);
+ void pathUpdated();
+
+private:
+ friend class QSGPathViewAttached;
+ Q_DISABLE_COPY(QSGPathView)
+ Q_DECLARE_PRIVATE(QSGPathView)
+};
+
+class QDeclarativeOpenMetaObject;
+class QSGPathViewAttached : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QSGPathView *view READ view CONSTANT)
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged)
+ Q_PROPERTY(bool onPath READ isOnPath NOTIFY pathChanged)
+
+public:
+ QSGPathViewAttached(QObject *parent);
+ ~QSGPathViewAttached();
+
+ QSGPathView *view() { return m_view; }
+
+ bool isCurrentItem() const { return m_isCurrent; }
+ void setIsCurrentItem(bool c) {
+ if (m_isCurrent != c) {
+ m_isCurrent = c;
+ emit currentItemChanged();
+ }
+ }
+
+ QVariant value(const QByteArray &name) const;
+ void setValue(const QByteArray &name, const QVariant &val);
+
+ bool isOnPath() const { return m_onPath; }
+ void setOnPath(bool on) {
+ if (on != m_onPath) {
+ m_onPath = on;
+ emit pathChanged();
+ }
+ }
+ qreal m_percent;
+
+Q_SIGNALS:
+ void currentItemChanged();
+ void pathChanged();
+
+private:
+ friend class QSGPathViewPrivate;
+ friend class QSGPathView;
+ QSGPathView *m_view;
+ QDeclarativeOpenMetaObject *m_metaobject;
+ bool m_onPath : 1;
+ bool m_isCurrent : 1;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGPathView)
+QML_DECLARE_TYPEINFO(QSGPathView, QML_HAS_ATTACHED_PROPERTIES)
+QT_END_HEADER
+
+#endif // QSGPATHVIEW_P_H
diff --git a/src/declarative/items/qsgpathview_p_p.h b/src/declarative/items/qsgpathview_p_p.h
new file mode 100644
index 0000000000..ed54f29abe
--- /dev/null
+++ b/src/declarative/items/qsgpathview_p_p.h
@@ -0,0 +1,193 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPATHVIEW_P_H
+#define QDECLARATIVEPATHVIEW_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 "qsgpathview_p.h"
+#include "qsgitem_p.h"
+#include "qsgvisualitemmodel_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <private/qdeclarativeanimation_p_p.h>
+#include <private/qdeclarativeguard_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeOpenMetaObjectType;
+class QSGPathViewAttached;
+class QSGPathViewPrivate : public QSGItemPrivate, public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGPathView)
+
+public:
+ QSGPathViewPrivate()
+ : path(0), currentIndex(0), currentItemOffset(0.0), startPc(0), lastDist(0)
+ , lastElapsed(0), offset(0.0), offsetAdj(0.0), mappedRange(1.0)
+ , stealMouse(false), ownModel(false), interactive(true), haveHighlightRange(true)
+ , autoHighlight(true), highlightUp(false), layoutScheduled(false)
+ , moving(false), flicking(false)
+ , dragMargin(0), deceleration(100)
+ , moveOffset(this, &QSGPathViewPrivate::setAdjustedOffset)
+ , firstIndex(-1), pathItems(-1), requestedIndex(-1)
+ , moveReason(Other), moveDirection(Shortest), attType(0), highlightComponent(0), highlightItem(0)
+ , moveHighlight(this, &QSGPathViewPrivate::setHighlightPosition)
+ , highlightPosition(0)
+ , highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightRangeMode(QSGPathView::StrictlyEnforceRange)
+ , highlightMoveDuration(300), modelCount(0)
+ {
+ }
+
+ void init();
+
+ void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
+ if ((newGeometry.size() != oldGeometry.size())
+ && (!highlightItem || item != highlightItem)) {
+ if (QSGPathViewAttached *att = attached(item))
+ att->m_percent = -1;
+ scheduleLayout();
+ }
+ }
+
+ void scheduleLayout() {
+ Q_Q(QSGPathView);
+ if (!layoutScheduled) {
+ layoutScheduled = true;
+ q->polish();
+ }
+ }
+
+ QSGItem *getItem(int modelIndex);
+ void releaseItem(QSGItem *item);
+ QSGPathViewAttached *attached(QSGItem *item);
+ void clear();
+ void updateMappedRange();
+ qreal positionOfIndex(qreal index) const;
+ void createHighlight();
+ void updateHighlight();
+ void setHighlightPosition(qreal pos);
+ bool isValid() const {
+ return model && model->count() > 0 && model->isValid() && path;
+ }
+
+ void handleMousePressEvent(QGraphicsSceneMouseEvent *event);
+ void handleMouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void handleMouseReleaseEvent(QGraphicsSceneMouseEvent *);
+
+ int calcCurrentIndex();
+ void updateCurrent();
+ static void fixOffsetCallback(void*);
+ void fixOffset();
+ void setOffset(qreal offset);
+ void setAdjustedOffset(qreal offset);
+ void regenerate();
+ void updateItem(QSGItem *, qreal);
+ void snapToCurrent();
+ QPointF pointNear(const QPointF &point, qreal *nearPercent=0) const;
+
+ QDeclarativePath *path;
+ int currentIndex;
+ QDeclarativeGuard<QSGItem> currentItem;
+ qreal currentItemOffset;
+ qreal startPc;
+ QPointF startPoint;
+ qreal lastDist;
+ int lastElapsed;
+ qreal offset;
+ qreal offsetAdj;
+ qreal mappedRange;
+ bool stealMouse : 1;
+ bool ownModel : 1;
+ bool interactive : 1;
+ bool haveHighlightRange : 1;
+ bool autoHighlight : 1;
+ bool highlightUp : 1;
+ bool layoutScheduled : 1;
+ bool moving : 1;
+ bool flicking : 1;
+ QElapsedTimer lastPosTime;
+ QPointF lastPos;
+ qreal dragMargin;
+ qreal deceleration;
+ QDeclarativeTimeLine tl;
+ QDeclarativeTimeLineValueProxy<QSGPathViewPrivate> moveOffset;
+ int firstIndex;
+ int pathItems;
+ int requestedIndex;
+ QList<QSGItem *> items;
+ QList<QSGItem *> itemCache;
+ QDeclarativeGuard<QSGVisualModel> model;
+ QVariant modelVariant;
+ enum MovementReason { Other, SetIndex, Mouse };
+ MovementReason moveReason;
+ enum MovementDirection { Shortest, Negative, Positive };
+ MovementDirection moveDirection;
+ QDeclarativeOpenMetaObjectType *attType;
+ QDeclarativeComponent *highlightComponent;
+ QSGItem *highlightItem;
+ QDeclarativeTimeLineValueProxy<QSGPathViewPrivate> moveHighlight;
+ qreal highlightPosition;
+ qreal highlightRangeStart;
+ qreal highlightRangeEnd;
+ QSGPathView::HighlightRangeMode highlightRangeMode;
+ int highlightMoveDuration;
+ int modelCount;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/items/qsgpincharea.cpp b/src/declarative/items/qsgpincharea.cpp
new file mode 100644
index 0000000000..e32f6bfe71
--- /dev/null
+++ b/src/declarative/items/qsgpincharea.cpp
@@ -0,0 +1,407 @@
+// Commit: 2ec2dc55ddf424f5a7acd0a4729ddd9af2d7c398
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtSG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpincharea_p_p.h"
+#include "qsgcanvas.h"
+
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qapplication.h>
+
+#include <float.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGPinch::QSGPinch()
+ : m_target(0), m_minScale(1.0), m_maxScale(1.0)
+ , m_minRotation(0.0), m_maxRotation(0.0)
+ , m_axis(NoDrag), m_xmin(-FLT_MAX), m_xmax(FLT_MAX)
+ , m_ymin(-FLT_MAX), m_ymax(FLT_MAX), m_active(false)
+{
+}
+
+QSGPinchAreaPrivate::~QSGPinchAreaPrivate()
+{
+ delete pinch;
+}
+
+QSGPinchArea::QSGPinchArea(QSGItem *parent)
+ : QSGItem(*(new QSGPinchAreaPrivate), parent)
+{
+ Q_D(QSGPinchArea);
+ d->init();
+}
+
+QSGPinchArea::~QSGPinchArea()
+{
+}
+
+bool QSGPinchArea::isEnabled() const
+{
+ Q_D(const QSGPinchArea);
+ return d->absorb;
+}
+
+void QSGPinchArea::setEnabled(bool a)
+{
+ Q_D(QSGPinchArea);
+ if (a != d->absorb) {
+ d->absorb = a;
+ emit enabledChanged();
+ }
+}
+
+void QSGPinchArea::touchEvent(QTouchEvent *event)
+{
+ Q_D(QSGPinchArea);
+ if (!d->absorb || !isVisible()) {
+ QSGItem::event(event);
+ return;
+ }
+
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ d->touchPoints.clear();
+ for (int i = 0; i < event->touchPoints().count(); ++i) {
+ if (!(event->touchPoints().at(i).state() & Qt::TouchPointReleased)) {
+ d->touchPoints << event->touchPoints().at(i);
+ }
+ }
+ updatePinch();
+ break;
+ case QEvent::TouchEnd:
+ d->touchPoints.clear();
+ updatePinch();
+ break;
+ default:
+ QSGItem::event(event);
+ }
+}
+
+void QSGPinchArea::updatePinch()
+{
+ Q_D(QSGPinchArea);
+ if (d->touchPoints.count() != 2) {
+ if (d->inPinch) {
+ d->stealMouse = false;
+ setKeepMouseGrab(false);
+ d->inPinch = false;
+ QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
+ QSGPinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(pinchCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(d->lastPoint1);
+ pe.setPoint2(d->lastPoint2);
+ emit pinchFinished(&pe);
+ d->pinchStartDist = 0;
+ if (d->pinch && d->pinch->target())
+ d->pinch->setActive(false);
+ }
+ return;
+ }
+ if (d->touchPoints.at(0).state() & Qt::TouchPointPressed
+ || d->touchPoints.at(1).state() & Qt::TouchPointPressed) {
+ d->sceneStartPoint1 = d->touchPoints.at(0).scenePos();
+ d->sceneStartPoint2 = d->touchPoints.at(1).scenePos();
+ d->inPinch = false;
+ d->pinchRejected = false;
+ } else if (!d->pinchRejected){
+ QSGItem *grabber = canvas() ? canvas()->mouseGrabberItem() : 0;
+ if (grabber == this || !grabber || !grabber->keepMouseGrab()) {
+ const int dragThreshold = QApplication::startDragDistance();
+ QPointF p1 = d->touchPoints.at(0).scenePos();
+ QPointF p2 = d->touchPoints.at(1).scenePos();
+ qreal dx = p1.x() - p2.x();
+ qreal dy = p1.y() - p2.y();
+ qreal dist = sqrt(dx*dx + dy*dy);
+ QPointF sceneCenter = (p1 + p2)/2;
+ qreal angle = QLineF(p1, p2).angle();
+ if (angle > 180)
+ angle -= 360;
+ if (!d->inPinch) {
+ if (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold
+ || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold
+ || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold
+ || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold) {
+ d->sceneStartCenter = sceneCenter;
+ d->sceneLastCenter = sceneCenter;
+ d->pinchStartCenter = mapFromScene(sceneCenter);
+ d->pinchStartDist = dist;
+ d->pinchStartAngle = angle;
+ d->pinchLastScale = 1.0;
+ d->pinchLastAngle = angle;
+ d->pinchRotation = 0.0;
+ d->lastPoint1 = d->touchPoints.at(0).pos();
+ d->lastPoint2 = d->touchPoints.at(1).pos();
+ QSGPinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(d->pinchStartCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(d->lastPoint1);
+ pe.setPoint2(d->lastPoint2);
+ emit pinchStarted(&pe);
+ if (pe.accepted()) {
+ d->inPinch = true;
+ d->stealMouse = true;
+ QSGCanvas *c = canvas();
+ if (c && c->mouseGrabberItem() != this)
+ grabMouse();
+ setKeepMouseGrab(true);
+ if (d->pinch && d->pinch->target()) {
+ d->pinchStartPos = pinch()->target()->pos();
+ d->pinchStartScale = d->pinch->target()->scale();
+ d->pinchStartRotation = d->pinch->target()->rotation();
+ d->pinch->setActive(true);
+ }
+ } else {
+ d->pinchRejected = true;
+ }
+ }
+ } else if (d->pinchStartDist > 0) {
+ qreal scale = dist / d->pinchStartDist;
+ qreal da = d->pinchLastAngle - angle;
+ if (da > 180)
+ da -= 360;
+ else if (da < -180)
+ da += 360;
+ d->pinchRotation += da;
+ QPointF pinchCenter = mapFromScene(sceneCenter);
+ QSGPinchEvent pe(pinchCenter, scale, angle, d->pinchRotation);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(mapFromScene(d->sceneLastCenter));
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(d->touchPoints.at(0).pos());
+ pe.setPoint2(d->touchPoints.at(1).pos());
+ d->pinchLastScale = scale;
+ d->sceneLastCenter = sceneCenter;
+ d->pinchLastAngle = angle;
+ d->lastPoint1 = d->touchPoints.at(0).pos();
+ d->lastPoint2 = d->touchPoints.at(1).pos();
+ emit pinchUpdated(&pe);
+ if (d->pinch && d->pinch->target()) {
+ qreal s = d->pinchStartScale * scale;
+ s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
+ pinch()->target()->setScale(s);
+ QPointF pos = sceneCenter - d->sceneStartCenter + d->pinchStartPos;
+ if (pinch()->axis() & QSGPinch::XAxis) {
+ qreal x = pos.x();
+ if (x < pinch()->xmin())
+ x = pinch()->xmin();
+ else if (x > pinch()->xmax())
+ x = pinch()->xmax();
+ pinch()->target()->setX(x);
+ }
+ if (pinch()->axis() & QSGPinch::YAxis) {
+ qreal y = pos.y();
+ if (y < pinch()->ymin())
+ y = pinch()->ymin();
+ else if (y > pinch()->ymax())
+ y = pinch()->ymax();
+ pinch()->target()->setY(y);
+ }
+ if (d->pinchStartRotation >= pinch()->minimumRotation()
+ && d->pinchStartRotation <= pinch()->maximumRotation()) {
+ qreal r = d->pinchRotation + d->pinchStartRotation;
+ r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation());
+ pinch()->target()->setRotation(r);
+ }
+ }
+ }
+ }
+ }
+}
+
+void QSGPinchArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ d->stealMouse = false;
+ if (!d->absorb)
+ QSGItem::mousePressEvent(event);
+ else {
+ setKeepMouseGrab(false);
+ event->setAccepted(true);
+ }
+}
+
+void QSGPinchArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ if (!d->absorb) {
+ QSGItem::mouseMoveEvent(event);
+ return;
+ }
+}
+
+void QSGPinchArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ d->stealMouse = false;
+ if (!d->absorb) {
+ QSGItem::mouseReleaseEvent(event);
+ } else {
+ QSGCanvas *c = canvas();
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+ }
+}
+
+void QSGPinchArea::mouseUngrabEvent()
+{
+ setKeepMouseGrab(false);
+}
+
+bool QSGPinchArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+
+ QSGCanvas *c = canvas();
+ QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ mouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ mousePressEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ mouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = c->mouseGrabberItem();
+ if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ return stealThisEvent;
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+ d->stealMouse = false;
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+ }
+ return false;
+}
+
+bool QSGPinchArea::childMouseEventFilter(QSGItem *i, QEvent *e)
+{
+ Q_D(QSGPinchArea);
+ if (!d->absorb || !isVisible())
+ return QSGItem::childMouseEventFilter(i, e);
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate: {
+ QTouchEvent *touch = static_cast<QTouchEvent*>(e);
+ d->touchPoints.clear();
+ for (int i = 0; i < touch->touchPoints().count(); ++i)
+ if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
+ d->touchPoints << touch->touchPoints().at(i);
+ updatePinch();
+ }
+ return d->inPinch;
+ case QEvent::TouchEnd:
+ d->touchPoints.clear();
+ updatePinch();
+ break;
+ default:
+ break;
+ }
+
+ return QSGItem::childMouseEventFilter(i, e);
+}
+
+void QSGPinchArea::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+void QSGPinchArea::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ QSGItem::itemChange(change, value);
+}
+
+QSGPinch *QSGPinchArea::pinch()
+{
+ Q_D(QSGPinchArea);
+ if (!d->pinch)
+ d->pinch = new QSGPinch;
+ return d->pinch;
+}
+
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/items/qsgpincharea_p.h b/src/declarative/items/qsgpincharea_p.h
new file mode 100644
index 0000000000..04fd815df3
--- /dev/null
+++ b/src/declarative/items/qsgpincharea_p.h
@@ -0,0 +1,310 @@
+// Commit: ce59628ba366800fe2f3afdadc37be02f98480a7
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtSG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPINCHAREA_H
+#define QSGPINCHAREA_H
+
+#include "qsgitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QSGPinch : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(Axis)
+ Q_PROPERTY(QSGItem *target READ target WRITE setTarget RESET resetTarget)
+ Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged)
+ Q_PROPERTY(qreal maximumScale READ maximumScale WRITE setMaximumScale NOTIFY maximumScaleChanged)
+ Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged)
+ Q_PROPERTY(qreal maximumRotation READ maximumRotation WRITE setMaximumRotation NOTIFY maximumRotationChanged)
+ Q_PROPERTY(Axis dragAxis READ axis WRITE setAxis NOTIFY dragAxisChanged)
+ Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged)
+ Q_PROPERTY(qreal maximumX READ xmax WRITE setXmax NOTIFY maximumXChanged)
+ 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)
+
+public:
+ QSGPinch();
+
+ QSGItem *target() const { return m_target; }
+ void setTarget(QSGItem *target) {
+ if (target == m_target)
+ return;
+ m_target = target;
+ emit targetChanged();
+ }
+ void resetTarget() {
+ if (!m_target)
+ return;
+ m_target = 0;
+ emit targetChanged();
+ }
+
+ qreal minimumScale() const { return m_minScale; }
+ void setMinimumScale(qreal s) {
+ if (s == m_minScale)
+ return;
+ m_minScale = s;
+ emit minimumScaleChanged();
+ }
+ qreal maximumScale() const { return m_maxScale; }
+ void setMaximumScale(qreal s) {
+ if (s == m_maxScale)
+ return;
+ m_maxScale = s;
+ emit maximumScaleChanged();
+ }
+
+ qreal minimumRotation() const { return m_minRotation; }
+ void setMinimumRotation(qreal r) {
+ if (r == m_minRotation)
+ return;
+ m_minRotation = r;
+ emit minimumRotationChanged();
+ }
+ qreal maximumRotation() const { return m_maxRotation; }
+ void setMaximumRotation(qreal r) {
+ if (r == m_maxRotation)
+ return;
+ m_maxRotation = r;
+ emit maximumRotationChanged();
+ }
+
+ enum Axis { NoDrag=0x00, XAxis=0x01, YAxis=0x02, XandYAxis=0x03 };
+ Axis axis() const { return m_axis; }
+ void setAxis(Axis a) {
+ if (a == m_axis)
+ return;
+ m_axis = a;
+ emit dragAxisChanged();
+ }
+
+ qreal xmin() const { return m_xmin; }
+ void setXmin(qreal x) {
+ if (x == m_xmin)
+ return;
+ m_xmin = x;
+ emit minimumXChanged();
+ }
+ qreal xmax() const { return m_xmax; }
+ void setXmax(qreal x) {
+ if (x == m_xmax)
+ return;
+ m_xmax = x;
+ emit maximumXChanged();
+ }
+ qreal ymin() const { return m_ymin; }
+ void setYmin(qreal y) {
+ if (y == m_ymin)
+ return;
+ m_ymin = y;
+ emit minimumYChanged();
+ }
+ qreal ymax() const { return m_ymax; }
+ void setYmax(qreal y) {
+ if (y == m_ymax)
+ return;
+ m_ymax = y;
+ emit maximumYChanged();
+ }
+
+ bool active() const { return m_active; }
+ void setActive(bool a) {
+ if (a == m_active)
+ return;
+ m_active = a;
+ emit activeChanged();
+ }
+
+signals:
+ void targetChanged();
+ void minimumScaleChanged();
+ void maximumScaleChanged();
+ void minimumRotationChanged();
+ void maximumRotationChanged();
+ void dragAxisChanged();
+ void minimumXChanged();
+ void maximumXChanged();
+ void minimumYChanged();
+ void maximumYChanged();
+ void activeChanged();
+
+private:
+ QSGItem *m_target;
+ qreal m_minScale;
+ qreal m_maxScale;
+ qreal m_minRotation;
+ qreal m_maxRotation;
+ Axis m_axis;
+ qreal m_xmin;
+ qreal m_xmax;
+ qreal m_ymin;
+ qreal m_ymax;
+ bool m_active;
+};
+
+class Q_AUTOTEST_EXPORT QSGPinchEvent : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPointF center READ center)
+ Q_PROPERTY(QPointF startCenter READ startCenter)
+ Q_PROPERTY(QPointF previousCenter READ previousCenter)
+ Q_PROPERTY(qreal scale READ scale)
+ Q_PROPERTY(qreal previousScale READ previousScale)
+ Q_PROPERTY(qreal angle READ angle)
+ Q_PROPERTY(qreal previousAngle READ previousAngle)
+ Q_PROPERTY(qreal rotation READ rotation)
+ Q_PROPERTY(QPointF point1 READ point1)
+ Q_PROPERTY(QPointF startPoint1 READ startPoint1)
+ Q_PROPERTY(QPointF point2 READ point2)
+ Q_PROPERTY(QPointF startPoint2 READ startPoint2)
+ Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
+
+public:
+ QSGPinchEvent(QPointF c, qreal s, qreal a, qreal r)
+ : QObject(), m_center(c), m_scale(s), m_angle(a), m_rotation(r), m_accepted(true) {}
+
+ QPointF center() const { return m_center; }
+ QPointF startCenter() const { return m_startCenter; }
+ void setStartCenter(QPointF c) { m_startCenter = c; }
+ QPointF previousCenter() const { return m_lastCenter; }
+ void setPreviousCenter(QPointF c) { m_lastCenter = c; }
+ qreal scale() const { return m_scale; }
+ qreal previousScale() const { return m_lastScale; }
+ void setPreviousScale(qreal s) { m_lastScale = s; }
+ qreal angle() const { return m_angle; }
+ qreal previousAngle() const { return m_lastAngle; }
+ void setPreviousAngle(qreal a) { m_lastAngle = a; }
+ qreal rotation() const { return m_rotation; }
+ QPointF point1() const { return m_point1; }
+ void setPoint1(QPointF p) { m_point1 = p; }
+ QPointF startPoint1() const { return m_startPoint1; }
+ void setStartPoint1(QPointF p) { m_startPoint1 = p; }
+ QPointF point2() const { return m_point2; }
+ void setPoint2(QPointF p) { m_point2 = p; }
+ QPointF startPoint2() const { return m_startPoint2; }
+ void setStartPoint2(QPointF p) { m_startPoint2 = p; }
+
+ bool accepted() const { return m_accepted; }
+ void setAccepted(bool a) { m_accepted = a; }
+
+private:
+ QPointF m_center;
+ QPointF m_startCenter;
+ QPointF m_lastCenter;
+ qreal m_scale;
+ qreal m_lastScale;
+ qreal m_angle;
+ qreal m_lastAngle;
+ qreal m_rotation;
+ QPointF m_point1;
+ QPointF m_point2;
+ QPointF m_startPoint1;
+ QPointF m_startPoint2;
+ bool m_accepted;
+};
+
+
+class QSGMouseEvent;
+class QSGPinchAreaPrivate;
+class Q_AUTOTEST_EXPORT QSGPinchArea : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(QSGPinch *pinch READ pinch CONSTANT)
+
+public:
+ QSGPinchArea(QSGItem *parent=0);
+ ~QSGPinchArea();
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ QSGPinch *pinch();
+
+Q_SIGNALS:
+ void enabledChanged();
+ void pinchStarted(QSGPinchEvent *pinch);
+ void pinchUpdated(QSGPinchEvent *pinch);
+ void pinchFinished(QSGPinchEvent *pinch);
+
+protected:
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseUngrabEvent();
+ virtual bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+ virtual bool childMouseEventFilter(QSGItem *i, QEvent *e);
+ virtual void touchEvent(QTouchEvent *event);
+
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ virtual void itemChange(ItemChange change, const ItemChangeData& value);
+
+private:
+ void updatePinch();
+ void handlePress();
+ void handleRelease();
+
+private:
+ Q_DISABLE_COPY(QSGPinchArea)
+ Q_DECLARE_PRIVATE(QSGPinchArea)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGPinch)
+QML_DECLARE_TYPE(QSGPinchEvent)
+QML_DECLARE_TYPE(QSGPinchArea)
+
+QT_END_HEADER
+
+#endif // QSGPINCHAREA_H
+
diff --git a/src/declarative/items/qsgpincharea_p_p.h b/src/declarative/items/qsgpincharea_p_p.h
new file mode 100644
index 0000000000..bdb3a51ef2
--- /dev/null
+++ b/src/declarative/items/qsgpincharea_p_p.h
@@ -0,0 +1,112 @@
+// Commit: 2ec2dc55ddf424f5a7acd0a4729ddd9af2d7c398
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtSG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPINCHAREA_P_H
+#define QSGPINCHAREA_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 <qevent.h>
+
+#include "qsgitem_p.h"
+#include "qsgpincharea_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGPinch;
+class QSGPinchAreaPrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGPinchArea)
+public:
+ QSGPinchAreaPrivate()
+ : absorb(true), stealMouse(false), inPinch(false)
+ , pinchRejected(false), pinch(0), pinchStartDist(0), pinchStartScale(1.0)
+ , pinchLastScale(1.0), pinchStartRotation(0.0), pinchStartAngle(0.0)
+ , pinchLastAngle(0.0), pinchRotation(0.0)
+ {
+ }
+
+ ~QSGPinchAreaPrivate();
+
+ void init()
+ {
+ Q_Q(QSGPinchArea);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFiltersChildMouseEvents(true);
+ }
+
+ bool absorb : 1;
+ bool stealMouse : 1;
+ bool inPinch : 1;
+ bool pinchRejected : 1;
+ QSGPinch *pinch;
+ QPointF sceneStartPoint1;
+ QPointF sceneStartPoint2;
+ QPointF lastPoint1;
+ QPointF lastPoint2;
+ qreal pinchStartDist;
+ qreal pinchStartScale;
+ qreal pinchLastScale;
+ qreal pinchStartRotation;
+ qreal pinchStartAngle;
+ qreal pinchLastAngle;
+ qreal pinchRotation;
+ QPointF sceneStartCenter;
+ QPointF pinchStartCenter;
+ QPointF sceneLastCenter;
+ QPointF pinchStartPos;
+ QList<QTouchEvent::TouchPoint> touchPoints;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGPINCHAREA_P_H
+
diff --git a/src/declarative/items/qsgpositioners.cpp b/src/declarative/items/qsgpositioners.cpp
new file mode 100644
index 0000000000..f174612af6
--- /dev/null
+++ b/src/declarative/items/qsgpositioners.cpp
@@ -0,0 +1,788 @@
+// Commit: 1f38d41854fa2daa51d938a4eb398752b1751e0b
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpositioners_p.h"
+#include "qsgpositioners_p_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <private/qdeclarativestate_p.h>
+#include <private/qdeclarativestategroup_p.h>
+#include <private/qdeclarativestateoperations_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static const QSGItemPrivate::ChangeTypes watchedChanges
+ = QSGItemPrivate::Geometry
+ | QSGItemPrivate::SiblingOrder
+ | QSGItemPrivate::Visibility
+ | QSGItemPrivate::Opacity
+ | QSGItemPrivate::Destroyed;
+
+void QSGBasePositionerPrivate::watchChanges(QSGItem *other)
+{
+ QSGItemPrivate *otherPrivate = QSGItemPrivate::get(other);
+ otherPrivate->addItemChangeListener(this, watchedChanges);
+}
+
+void QSGBasePositionerPrivate::unwatchChanges(QSGItem* other)
+{
+ QSGItemPrivate *otherPrivate = QSGItemPrivate::get(other);
+ otherPrivate->removeItemChangeListener(this, watchedChanges);
+}
+
+QSGBasePositioner::QSGBasePositioner(PositionerType at, QSGItem *parent)
+ : QSGImplicitSizeItem(*(new QSGBasePositionerPrivate), parent)
+{
+ Q_D(QSGBasePositioner);
+ d->init(at);
+}
+
+QSGBasePositioner::QSGBasePositioner(QSGBasePositionerPrivate &dd, PositionerType at, QSGItem *parent)
+ : QSGImplicitSizeItem(dd, parent)
+{
+ Q_D(QSGBasePositioner);
+ d->init(at);
+}
+
+QSGBasePositioner::~QSGBasePositioner()
+{
+ Q_D(QSGBasePositioner);
+ for (int i = 0; i < positionedItems.count(); ++i)
+ d->unwatchChanges(positionedItems.at(i).item);
+ positionedItems.clear();
+}
+
+int QSGBasePositioner::spacing() const
+{
+ Q_D(const QSGBasePositioner);
+ return d->spacing;
+}
+
+void QSGBasePositioner::setSpacing(int s)
+{
+ Q_D(QSGBasePositioner);
+ if (s==d->spacing)
+ return;
+ d->spacing = s;
+ prePositioning();
+ emit spacingChanged();
+}
+
+QDeclarativeTransition *QSGBasePositioner::move() const
+{
+ Q_D(const QSGBasePositioner);
+ return d->moveTransition;
+}
+
+void QSGBasePositioner::setMove(QDeclarativeTransition *mt)
+{
+ Q_D(QSGBasePositioner);
+ if (mt == d->moveTransition)
+ return;
+ d->moveTransition = mt;
+ emit moveChanged();
+}
+
+QDeclarativeTransition *QSGBasePositioner::add() const
+{
+ Q_D(const QSGBasePositioner);
+ return d->addTransition;
+}
+
+void QSGBasePositioner::setAdd(QDeclarativeTransition *add)
+{
+ Q_D(QSGBasePositioner);
+ if (add == d->addTransition)
+ return;
+
+ d->addTransition = add;
+ emit addChanged();
+}
+
+void QSGBasePositioner::componentComplete()
+{
+ QSGItem::componentComplete();
+ positionedItems.reserve(childItems().count());
+ prePositioning();
+ reportConflictingAnchors();
+}
+
+void QSGBasePositioner::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QSGBasePositioner);
+ if (change == ItemChildAddedChange){
+ prePositioning();
+ } else if (change == ItemChildRemovedChange) {
+ QSGItem *child = value.item;
+ QSGBasePositioner::PositionedItem posItem(child);
+ int idx = positionedItems.find(posItem);
+ if (idx >= 0) {
+ d->unwatchChanges(child);
+ positionedItems.remove(idx);
+ }
+ prePositioning();
+ }
+
+ QSGItem::itemChange(change, value);
+}
+
+void QSGBasePositioner::prePositioning()
+{
+ Q_D(QSGBasePositioner);
+ if (!isComponentComplete())
+ return;
+
+ if (d->doingPositioning)
+ return;
+
+ d->queuedPositioning = false;
+ d->doingPositioning = true;
+ //Need to order children by creation order modified by stacking order
+ QList<QSGItem *> children = childItems();
+
+ QPODVector<PositionedItem,8> oldItems;
+ positionedItems.copyAndClear(oldItems);
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QSGItem *child = children.at(ii);
+ QSGItemPrivate *childPrivate = QSGItemPrivate::get(child);
+ PositionedItem *item = 0;
+ PositionedItem posItem(child);
+ int wIdx = oldItems.find(posItem);
+ if (wIdx < 0) {
+ d->watchChanges(child);
+ positionedItems.append(posItem);
+ item = &positionedItems[positionedItems.count()-1];
+ item->isNew = true;
+ if (child->opacity() <= 0.0 || !childPrivate->explicitVisible || !child->width() || !child->height())
+ item->isVisible = false;
+ } else {
+ item = &oldItems[wIdx];
+ // Items are only omitted from positioning if they are explicitly hidden
+ // i.e. their positioning is not affected if an ancestor is hidden.
+ if (child->opacity() <= 0.0 || !childPrivate->explicitVisible || !child->width() || !child->height()) {
+ item->isVisible = false;
+ } else if (!item->isVisible) {
+ item->isVisible = true;
+ item->isNew = true;
+ } else {
+ item->isNew = false;
+ }
+ positionedItems.append(*item);
+ }
+ }
+ QSizeF contentSize;
+ doPositioning(&contentSize);
+ if(d->addTransition || d->moveTransition)
+ finishApplyTransitions();
+ d->doingPositioning = false;
+ //Set implicit size to the size of its children
+ setImplicitHeight(contentSize.height());
+ setImplicitWidth(contentSize.width());
+}
+
+void QSGBasePositioner::positionX(int x, const PositionedItem &target)
+{
+ Q_D(QSGBasePositioner);
+ if(d->type == Horizontal || d->type == Both){
+ if (target.isNew) {
+ if (!d->addTransition)
+ target.item->setX(x);
+ else
+ d->addActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
+ } else if (x != target.item->x()) {
+ if (!d->moveTransition)
+ target.item->setX(x);
+ else
+ d->moveActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
+ }
+ }
+}
+
+void QSGBasePositioner::positionY(int y, const PositionedItem &target)
+{
+ Q_D(QSGBasePositioner);
+ if(d->type == Vertical || d->type == Both){
+ if (target.isNew) {
+ if (!d->addTransition)
+ target.item->setY(y);
+ else
+ d->addActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
+ } else if (y != target.item->y()) {
+ if (!d->moveTransition)
+ target.item->setY(y);
+ else
+ d->moveActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
+ }
+ }
+}
+
+void QSGBasePositioner::finishApplyTransitions()
+{
+ Q_D(QSGBasePositioner);
+ // Note that if a transition is not set the transition manager will
+ // apply the changes directly, in the case add/move aren't set
+ d->addTransitionManager.transition(d->addActions, d->addTransition);
+ d->moveTransitionManager.transition(d->moveActions, d->moveTransition);
+ d->addActions.clear();
+ d->moveActions.clear();
+}
+
+QSGColumn::QSGColumn(QSGItem *parent)
+: QSGBasePositioner(Vertical, parent)
+{
+}
+
+void QSGColumn::doPositioning(QSizeF *contentSize)
+{
+ int voffset = 0;
+
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (!child.item || !child.isVisible)
+ continue;
+
+ if(child.item->y() != voffset)
+ positionY(voffset, child);
+
+ contentSize->setWidth(qMax(contentSize->width(), child.item->width()));
+
+ voffset += child.item->height();
+ voffset += spacing();
+ }
+
+ contentSize->setHeight(voffset - spacing());
+}
+
+void QSGColumn::reportConflictingAnchors()
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
+ if (anchors) {
+ QSGAnchors::Anchors usedAnchors = anchors->usedAnchors();
+ if (usedAnchors & QSGAnchors::TopAnchor ||
+ usedAnchors & QSGAnchors::BottomAnchor ||
+ usedAnchors & QSGAnchors::VCenterAnchor ||
+ anchors->fill() || anchors->centerIn()) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ }
+ if (d->anchorConflict) {
+ qmlInfo(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column";
+ }
+}
+
+QSGRow::QSGRow(QSGItem *parent)
+: QSGBasePositioner(Horizontal, parent)
+{
+}
+
+Qt::LayoutDirection QSGRow::layoutDirection() const
+{
+ return QSGBasePositionerPrivate::getLayoutDirection(this);
+}
+
+void QSGRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate* >(QSGBasePositionerPrivate::get(this));
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ // For RTL layout the positioning changes when the width changes.
+ if (d->layoutDirection == Qt::RightToLeft)
+ d->addItemChangeListener(d, QSGItemPrivate::Geometry);
+ else
+ d->removeItemChangeListener(d, QSGItemPrivate::Geometry);
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+Qt::LayoutDirection QSGRow::effectiveLayoutDirection() const
+{
+ return QSGBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QSGRow::doPositioning(QSizeF *contentSize)
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate* >(QSGBasePositionerPrivate::get(this));
+ int hoffset = 0;
+
+ QList<int> hoffsets;
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (!child.item || !child.isVisible)
+ continue;
+
+ if (d->isLeftToRight()) {
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ } else {
+ hoffsets << hoffset;
+ }
+
+ contentSize->setHeight(qMax(contentSize->height(), child.item->height()));
+
+ hoffset += child.item->width();
+ hoffset += spacing();
+ }
+
+ contentSize->setWidth(hoffset - spacing());
+
+ if (d->isLeftToRight())
+ return;
+
+ //Right to Left layout
+ int end = 0;
+ if (!widthValid())
+ end = contentSize->width();
+ else
+ end = width();
+
+ int acc = 0;
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (!child.item || !child.isVisible)
+ continue;
+ hoffset = end - hoffsets[acc++] - child.item->width();
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ }
+}
+
+void QSGRow::reportConflictingAnchors()
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
+ if (anchors) {
+ QSGAnchors::Anchors usedAnchors = anchors->usedAnchors();
+ if (usedAnchors & QSGAnchors::LeftAnchor ||
+ usedAnchors & QSGAnchors::RightAnchor ||
+ usedAnchors & QSGAnchors::HCenterAnchor ||
+ anchors->fill() || anchors->centerIn()) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ }
+ if (d->anchorConflict)
+ qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row";
+}
+
+QSGGrid::QSGGrid(QSGItem *parent) :
+ QSGBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight)
+{
+}
+
+void QSGGrid::setColumns(const int columns)
+{
+ if (columns == m_columns)
+ return;
+ m_columns = columns;
+ prePositioning();
+ emit columnsChanged();
+}
+
+void QSGGrid::setRows(const int rows)
+{
+ if (rows == m_rows)
+ return;
+ m_rows = rows;
+ prePositioning();
+ emit rowsChanged();
+}
+
+QSGGrid::Flow QSGGrid::flow() const
+{
+ return m_flow;
+}
+
+void QSGGrid::setFlow(Flow flow)
+{
+ if (m_flow != flow) {
+ m_flow = flow;
+ prePositioning();
+ emit flowChanged();
+ }
+}
+
+Qt::LayoutDirection QSGGrid::layoutDirection() const
+{
+ return QSGBasePositionerPrivate::getLayoutDirection(this);
+}
+
+void QSGGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ // For RTL layout the positioning changes when the width changes.
+ if (d->layoutDirection == Qt::RightToLeft)
+ d->addItemChangeListener(d, QSGItemPrivate::Geometry);
+ else
+ d->removeItemChangeListener(d, QSGItemPrivate::Geometry);
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+Qt::LayoutDirection QSGGrid::effectiveLayoutDirection() const
+{
+ return QSGBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QSGGrid::doPositioning(QSizeF *contentSize)
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
+ int c = m_columns;
+ int r = m_rows;
+ //Is allocating the extra QPODVector too much overhead?
+ QPODVector<PositionedItem, 8> visibleItems;//we aren't concerned with invisible items
+ visibleItems.reserve(positionedItems.count());
+ for(int i=0; i<positionedItems.count(); i++)
+ if(positionedItems[i].item && positionedItems[i].isVisible)
+ visibleItems.append(positionedItems[i]);
+
+ int numVisible = visibleItems.count();
+ if (m_columns <= 0 && m_rows <= 0){
+ c = 4;
+ r = (numVisible+3)/4;
+ } else if (m_rows <= 0){
+ r = (numVisible+(m_columns-1))/m_columns;
+ } else if (m_columns <= 0){
+ c = (numVisible+(m_rows-1))/m_rows;
+ }
+
+ if(r==0 || c==0)
+ return; //Nothing to do
+
+ QList<int> maxColWidth;
+ QList<int> maxRowHeight;
+ int childIndex =0;
+ if (m_flow == LeftToRight) {
+ for (int i=0; i < r; i++){
+ for (int j=0; j < c; j++){
+ if (j==0)
+ maxRowHeight << 0;
+ if (i==0)
+ maxColWidth << 0;
+
+ if (childIndex == visibleItems.count())
+ break;
+
+ const PositionedItem &child = visibleItems.at(childIndex++);
+ if (child.item->width() > maxColWidth[j])
+ maxColWidth[j] = child.item->width();
+ if (child.item->height() > maxRowHeight[i])
+ maxRowHeight[i] = child.item->height();
+ }
+ }
+ } else {
+ for (int j=0; j < c; j++){
+ for (int i=0; i < r; i++){
+ if (j==0)
+ maxRowHeight << 0;
+ if (i==0)
+ maxColWidth << 0;
+
+ if (childIndex == visibleItems.count())
+ break;
+
+ const PositionedItem &child = visibleItems.at(childIndex++);
+ if (child.item->width() > maxColWidth[j])
+ maxColWidth[j] = child.item->width();
+ if (child.item->height() > maxRowHeight[i])
+ maxRowHeight[i] = child.item->height();
+ }
+ }
+ }
+
+ int widthSum = 0;
+ for (int j=0; j < maxColWidth.size(); j++){
+ if (j)
+ widthSum += spacing();
+ widthSum += maxColWidth[j];
+ }
+
+ int heightSum = 0;
+ for (int i=0; i < maxRowHeight.size(); i++){
+ if (i)
+ heightSum += spacing();
+ heightSum += maxRowHeight[i];
+ }
+
+ contentSize->setHeight(heightSum);
+ contentSize->setWidth(widthSum);
+
+ int end = 0;
+ if (widthValid())
+ end = width();
+ else
+ end = widthSum;
+
+ int xoffset=0;
+ if (!d->isLeftToRight())
+ xoffset = end;
+ int yoffset=0;
+ int curRow =0;
+ int curCol =0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ const PositionedItem &child = visibleItems.at(i);
+ int childXOffset = xoffset;
+ if (!d->isLeftToRight())
+ childXOffset -= child.item->width();
+ if ((child.item->x() != childXOffset) || (child.item->y() != yoffset)){
+ positionX(childXOffset, child);
+ positionY(yoffset, child);
+ }
+
+ if (m_flow == LeftToRight) {
+ if (d->isLeftToRight())
+ xoffset += maxColWidth[curCol]+spacing();
+ else
+ xoffset -= maxColWidth[curCol]+spacing();
+ curCol++;
+ curCol%=c;
+ if (!curCol){
+ yoffset += maxRowHeight[curRow]+spacing();
+ if (d->isLeftToRight())
+ xoffset = 0;
+ else
+ xoffset = end;
+ curRow++;
+ if (curRow>=r)
+ break;
+ }
+ } else {
+ yoffset+=maxRowHeight[curRow]+spacing();
+ curRow++;
+ curRow%=r;
+ if (!curRow){
+ if (d->isLeftToRight())
+ xoffset += maxColWidth[curCol]+spacing();
+ else
+ xoffset -= maxColWidth[curCol]+spacing();
+ yoffset=0;
+ curCol++;
+ if (curCol>=c)
+ break;
+ }
+ }
+ }
+}
+
+void QSGGrid::reportConflictingAnchors()
+{
+ QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
+ if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ if (d->anchorConflict)
+ qmlInfo(this) << "Cannot specify anchors for items inside Grid";
+}
+
+class QSGFlowPrivate : public QSGBasePositionerPrivate
+{
+ Q_DECLARE_PUBLIC(QSGFlow)
+
+public:
+ QSGFlowPrivate()
+ : QSGBasePositionerPrivate(), flow(QSGFlow::LeftToRight)
+ {}
+
+ QSGFlow::Flow flow;
+};
+
+QSGFlow::QSGFlow(QSGItem *parent)
+: QSGBasePositioner(*(new QSGFlowPrivate), Both, parent)
+{
+ Q_D(QSGFlow);
+ // Flow layout requires relayout if its own size changes too.
+ d->addItemChangeListener(d, QSGItemPrivate::Geometry);
+}
+
+QSGFlow::Flow QSGFlow::flow() const
+{
+ Q_D(const QSGFlow);
+ return d->flow;
+}
+
+void QSGFlow::setFlow(Flow flow)
+{
+ Q_D(QSGFlow);
+ if (d->flow != flow) {
+ d->flow = flow;
+ prePositioning();
+ emit flowChanged();
+ }
+}
+
+Qt::LayoutDirection QSGFlow::layoutDirection() const
+{
+ Q_D(const QSGFlow);
+ return d->layoutDirection;
+}
+
+void QSGFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QSGFlow);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+Qt::LayoutDirection QSGFlow::effectiveLayoutDirection() const
+{
+ return QSGBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QSGFlow::doPositioning(QSizeF *contentSize)
+{
+ Q_D(QSGFlow);
+
+ int hoffset = 0;
+ int voffset = 0;
+ int linemax = 0;
+ QList<int> hoffsets;
+
+ for (int i = 0; i < positionedItems.count(); ++i) {
+ const PositionedItem &child = positionedItems.at(i);
+ if (!child.item || !child.isVisible)
+ continue;
+
+ if (d->flow == LeftToRight) {
+ if (widthValid() && hoffset && hoffset + child.item->width() > width()) {
+ hoffset = 0;
+ voffset += linemax + spacing();
+ linemax = 0;
+ }
+ } else {
+ if (heightValid() && voffset && voffset + child.item->height() > height()) {
+ voffset = 0;
+ hoffset += linemax + spacing();
+ linemax = 0;
+ }
+ }
+
+ if (d->isLeftToRight()) {
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ } else {
+ hoffsets << hoffset;
+ }
+ if (child.item->y() != voffset)
+ positionY(voffset, child);
+
+ contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width()));
+ contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height()));
+
+ if (d->flow == LeftToRight) {
+ hoffset += child.item->width();
+ hoffset += spacing();
+ linemax = qMax(linemax, qCeil(child.item->height()));
+ } else {
+ voffset += child.item->height();
+ voffset += spacing();
+ linemax = qMax(linemax, qCeil(child.item->width()));
+ }
+ }
+ if (d->isLeftToRight())
+ return;
+
+ int end;
+ if (widthValid())
+ end = width();
+ else
+ end = contentSize->width();
+ int acc = 0;
+ for (int i = 0; i < positionedItems.count(); ++i) {
+ const PositionedItem &child = positionedItems.at(i);
+ if (!child.item || !child.isVisible)
+ continue;
+ hoffset = end - hoffsets[acc++] - child.item->width();
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ }
+}
+
+void QSGFlow::reportConflictingAnchors()
+{
+ Q_D(QSGFlow);
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
+ if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ if (d->anchorConflict)
+ qmlInfo(this) << "Cannot specify anchors for items inside Flow";
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgpositioners_p.h b/src/declarative/items/qsgpositioners_p.h
new file mode 100644
index 0000000000..eb0e73456b
--- /dev/null
+++ b/src/declarative/items/qsgpositioners_p.h
@@ -0,0 +1,242 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPOSITIONERS_P_H
+#define QSGPOSITIONERS_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+
+#include <private/qdeclarativestate_p.h>
+#include <private/qpodvector_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGBasePositionerPrivate;
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGBasePositioner : public QSGImplicitSizeItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
+ Q_PROPERTY(QDeclarativeTransition *move READ move WRITE setMove NOTIFY moveChanged)
+ Q_PROPERTY(QDeclarativeTransition *add READ add WRITE setAdd NOTIFY addChanged)
+public:
+ enum PositionerType { None = 0x0, Horizontal = 0x1, Vertical = 0x2, Both = 0x3 };
+ QSGBasePositioner(PositionerType, QSGItem *parent);
+ ~QSGBasePositioner();
+
+ int spacing() const;
+ void setSpacing(int);
+
+ QDeclarativeTransition *move() const;
+ void setMove(QDeclarativeTransition *);
+
+ QDeclarativeTransition *add() const;
+ void setAdd(QDeclarativeTransition *);
+
+protected:
+ QSGBasePositioner(QSGBasePositionerPrivate &dd, PositionerType at, QSGItem *parent);
+ virtual void componentComplete();
+ virtual void itemChange(ItemChange, const ItemChangeData &);
+ void finishApplyTransitions();
+
+Q_SIGNALS:
+ void spacingChanged();
+ void moveChanged();
+ void addChanged();
+
+protected Q_SLOTS:
+ void prePositioning();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize)=0;
+ virtual void reportConflictingAnchors()=0;
+ class PositionedItem {
+ public :
+ PositionedItem(QSGItem *i) : item(i), isNew(false), isVisible(true) {}
+ bool operator==(const PositionedItem &other) const { return other.item == item; }
+ QSGItem *item;
+ bool isNew;
+ bool isVisible;
+ };
+
+ QPODVector<PositionedItem,8> positionedItems;
+ void positionX(int,const PositionedItem &target);
+ void positionY(int,const PositionedItem &target);
+
+private:
+ Q_DISABLE_COPY(QSGBasePositioner)
+ Q_DECLARE_PRIVATE(QSGBasePositioner)
+};
+
+class Q_AUTOTEST_EXPORT QSGColumn : public QSGBasePositioner
+{
+ Q_OBJECT
+public:
+ QSGColumn(QSGItem *parent=0);
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+private:
+ Q_DISABLE_COPY(QSGColumn)
+};
+
+class Q_AUTOTEST_EXPORT QSGRow: public QSGBasePositioner
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
+public:
+ QSGRow(QSGItem *parent=0);
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection (Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+Q_SIGNALS:
+ void layoutDirectionChanged();
+ void effectiveLayoutDirectionChanged();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+private:
+ Q_DISABLE_COPY(QSGRow)
+};
+
+class Q_AUTOTEST_EXPORT QSGGrid : public QSGBasePositioner
+{
+ Q_OBJECT
+ Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
+ Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged)
+ 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)
+
+public:
+ QSGGrid(QSGItem *parent=0);
+
+ int rows() const {return m_rows;}
+ void setRows(const int rows);
+
+ int columns() const {return m_columns;}
+ void setColumns(const int columns);
+
+ Q_ENUMS(Flow)
+ enum Flow { LeftToRight, TopToBottom };
+ Flow flow() const;
+ void setFlow(Flow);
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection (Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+Q_SIGNALS:
+ void rowsChanged();
+ void columnsChanged();
+ void flowChanged();
+ void layoutDirectionChanged();
+ void effectiveLayoutDirectionChanged();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+
+private:
+ int m_rows;
+ int m_columns;
+ Flow m_flow;
+ Q_DISABLE_COPY(QSGGrid)
+};
+
+class QSGFlowPrivate;
+class Q_AUTOTEST_EXPORT QSGFlow: public QSGBasePositioner
+{
+ Q_OBJECT
+ 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)
+public:
+ QSGFlow(QSGItem *parent=0);
+
+ Q_ENUMS(Flow)
+ enum Flow { LeftToRight, TopToBottom };
+ Flow flow() const;
+ void setFlow(Flow);
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection (Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+Q_SIGNALS:
+ void flowChanged();
+ void layoutDirectionChanged();
+ void effectiveLayoutDirectionChanged();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+protected:
+ QSGFlow(QSGFlowPrivate &dd, QSGItem *parent);
+private:
+ Q_DISABLE_COPY(QSGFlow)
+ Q_DECLARE_PRIVATE(QSGFlow)
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGColumn)
+QML_DECLARE_TYPE(QSGRow)
+QML_DECLARE_TYPE(QSGGrid)
+QML_DECLARE_TYPE(QSGFlow)
+
+QT_END_HEADER
+
+#endif // QSGPOSITIONERS_P_H
diff --git a/src/declarative/items/qsgpositioners_p_p.h b/src/declarative/items/qsgpositioners_p_p.h
new file mode 100644
index 0000000000..241cbcfa3c
--- /dev/null
+++ b/src/declarative/items/qsgpositioners_p_p.h
@@ -0,0 +1,173 @@
+// Commit: 2c7cab4172f1acc86fd49345a2847417e162f2c3
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPOSITIONERS_P_P_H
+#define QSGPOSITIONERS_P_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 "qsgpositioners_p.h"
+#include "qsgimplicitsizeitem_p_p.h"
+
+#include <private/qdeclarativestate_p.h>
+#include <private/qdeclarativetransitionmanager_p_p.h>
+#include <private/qdeclarativestateoperations_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGBasePositionerPrivate : public QSGImplicitSizeItemPrivate, public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGBasePositioner)
+
+public:
+ QSGBasePositionerPrivate()
+ : spacing(0), type(QSGBasePositioner::None)
+ , moveTransition(0), addTransition(0), queuedPositioning(false)
+ , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight)
+ {
+ }
+
+ void init(QSGBasePositioner::PositionerType at)
+ {
+ type = at;
+ }
+
+ int spacing;
+
+ QSGBasePositioner::PositionerType type;
+ QDeclarativeTransition *moveTransition;
+ QDeclarativeTransition *addTransition;
+ QDeclarativeStateOperation::ActionList addActions;
+ QDeclarativeStateOperation::ActionList moveActions;
+ QDeclarativeTransitionManager addTransitionManager;
+ QDeclarativeTransitionManager moveTransitionManager;
+
+ void watchChanges(QSGItem *other);
+ void unwatchChanges(QSGItem* other);
+ bool queuedPositioning : 1;
+ bool doingPositioning : 1;
+ bool anchorConflict : 1;
+
+ Qt::LayoutDirection layoutDirection;
+
+ void schedulePositioning()
+ {
+ Q_Q(QSGBasePositioner);
+ if(!queuedPositioning){
+ QTimer::singleShot(0,q,SLOT(prePositioning()));
+ queuedPositioning = true;
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QSGBasePositioner);
+ if (type != QSGBasePositioner::Vertical)
+ q->prePositioning();
+ }
+ bool isLeftToRight() const {
+ if (type == QSGBasePositioner::Vertical)
+ return true;
+ else
+ return effectiveLayoutMirror ? layoutDirection == Qt::RightToLeft : layoutDirection == Qt::LeftToRight;
+ }
+
+ virtual void itemSiblingOrderChanged(QSGItem* other)
+ {
+ Q_UNUSED(other);
+ //Delay is due to many children often being reordered at once
+ //And we only want to reposition them all once
+ schedulePositioning();
+ }
+
+ void itemGeometryChanged(QSGItem *, const QRectF &newGeometry, const QRectF &oldGeometry)
+ {
+ Q_Q(QSGBasePositioner);
+ if (newGeometry.size() != oldGeometry.size())
+ q->prePositioning();
+ }
+
+ virtual void itemVisibilityChanged(QSGItem *)
+ {
+ schedulePositioning();
+ }
+ virtual void itemOpacityChanged(QSGItem *)
+ {
+ Q_Q(QSGBasePositioner);
+ q->prePositioning();
+ }
+
+ void itemDestroyed(QSGItem *item)
+ {
+ Q_Q(QSGBasePositioner);
+ q->positionedItems.removeOne(QSGBasePositioner::PositionedItem(item));
+ }
+
+ static Qt::LayoutDirection getLayoutDirection(const QSGBasePositioner *positioner)
+ {
+ return positioner->d_func()->layoutDirection;
+ }
+
+ static Qt::LayoutDirection getEffectiveLayoutDirection(const QSGBasePositioner *positioner)
+ {
+ if (positioner->d_func()->effectiveLayoutMirror)
+ return positioner->d_func()->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return positioner->d_func()->layoutDirection;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGPOSITIONERS_P_P_H
diff --git a/src/declarative/items/qsgrectangle.cpp b/src/declarative/items/qsgrectangle.cpp
new file mode 100644
index 0000000000..247d6336b2
--- /dev/null
+++ b/src/declarative/items/qsgrectangle.cpp
@@ -0,0 +1,286 @@
+// Commit: acc903853d5ac54d646d324b7386c998bc07d464
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrectangle_p.h"
+#include "qsgrectangle_p_p.h"
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+
+#include <QtGui/qpixmapcache.h>
+#include <QtCore/qstringbuilder.h>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+// XXX todo - should we change rectangle to draw entirely within its width/height?
+
+QSGPen::QSGPen(QObject *parent)
+: QObject(parent), _width(1), _color("#000000"), _valid(false)
+{
+}
+
+QColor QSGPen::color() const
+{
+ return _color;
+}
+
+void QSGPen::setColor(const QColor &c)
+{
+ _color = c;
+ _valid = (_color.alpha() && _width >= 1) ? true : false;
+ emit penChanged();
+}
+
+int QSGPen::width() const
+{
+ return _width;
+}
+
+void QSGPen::setWidth(int w)
+{
+ if (_width == w && _valid)
+ return;
+
+ _width = w;
+ _valid = (_color.alpha() && _width >= 1) ? true : false;
+ emit penChanged();
+}
+
+bool QSGPen::isValid() const
+{
+ return _valid;
+}
+
+QSGGradientStop::QSGGradientStop(QObject *parent)
+: QObject(parent)
+{
+}
+
+qreal QSGGradientStop::position() const
+{
+ return m_position;
+}
+
+void QSGGradientStop::setPosition(qreal position)
+{
+ m_position = position; updateGradient();
+}
+
+QColor QSGGradientStop::color() const
+{
+ return m_color;
+}
+
+void QSGGradientStop::setColor(const QColor &color)
+{
+ m_color = color; updateGradient();
+}
+
+void QSGGradientStop::updateGradient()
+{
+ if (QSGGradient *grad = qobject_cast<QSGGradient*>(parent()))
+ grad->doUpdate();
+}
+
+QSGGradient::QSGGradient(QObject *parent)
+: QObject(parent), m_gradient(0)
+{
+}
+
+QSGGradient::~QSGGradient()
+{
+ delete m_gradient;
+}
+
+QDeclarativeListProperty<QSGGradientStop> QSGGradient::stops()
+{
+ return QDeclarativeListProperty<QSGGradientStop>(this, m_stops);
+}
+
+const QGradient *QSGGradient::gradient() const
+{
+ if (!m_gradient && !m_stops.isEmpty()) {
+ m_gradient = new QLinearGradient(0,0,0,1.0);
+ for (int i = 0; i < m_stops.count(); ++i) {
+ const QSGGradientStop *stop = m_stops.at(i);
+ m_gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
+ m_gradient->setColorAt(stop->position(), stop->color());
+ }
+ }
+
+ return m_gradient;
+}
+
+void QSGGradient::doUpdate()
+{
+ delete m_gradient;
+ m_gradient = 0;
+ emit updated();
+}
+
+int QSGRectanglePrivate::doUpdateSlotIdx = -1;
+
+QSGRectangle::QSGRectangle(QSGItem *parent)
+: QSGItem(*(new QSGRectanglePrivate), parent)
+{
+ setFlag(ItemHasContents);
+}
+
+void QSGRectangle::doUpdate()
+{
+ Q_D(QSGRectangle);
+ const int pw = d->pen && d->pen->isValid() ? d->pen->width() : 0;
+ d->setPaintMargin((pw+1)/2);
+ update();
+}
+
+QSGPen *QSGRectangle::border()
+{
+ Q_D(QSGRectangle);
+ return d->getPen();
+}
+
+QSGGradient *QSGRectangle::gradient() const
+{
+ Q_D(const QSGRectangle);
+ return d->gradient;
+}
+
+void QSGRectangle::setGradient(QSGGradient *gradient)
+{
+ Q_D(QSGRectangle);
+ if (d->gradient == gradient)
+ return;
+ static int updatedSignalIdx = -1;
+ if (updatedSignalIdx < 0)
+ updatedSignalIdx = QSGGradient::staticMetaObject.indexOfSignal("updated()");
+ if (d->doUpdateSlotIdx < 0)
+ d->doUpdateSlotIdx = QSGRectangle::staticMetaObject.indexOfSlot("doUpdate()");
+ if (d->gradient)
+ QMetaObject::disconnect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
+ d->gradient = gradient;
+ if (d->gradient)
+ QMetaObject::connect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
+ update();
+}
+
+qreal QSGRectangle::radius() const
+{
+ Q_D(const QSGRectangle);
+ return d->radius;
+}
+
+void QSGRectangle::setRadius(qreal radius)
+{
+ Q_D(QSGRectangle);
+ if (d->radius == radius)
+ return;
+
+ d->radius = radius;
+ update();
+ emit radiusChanged();
+}
+
+QColor QSGRectangle::color() const
+{
+ Q_D(const QSGRectangle);
+ return d->color;
+}
+
+void QSGRectangle::setColor(const QColor &c)
+{
+ Q_D(QSGRectangle);
+ if (d->color == c)
+ return;
+
+ d->color = c;
+ update();
+ emit colorChanged();
+}
+
+QSGNode *QSGRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+ Q_D(QSGRectangle);
+
+ if (width() <= 0 || height() <= 0) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
+ if (!rectangle) rectangle = d->sceneGraphContext()->createRectangleNode();
+
+ rectangle->setRect(QRectF(0, 0, width(), height()));
+ rectangle->setColor(d->color);
+
+ if (d->pen && d->pen->isValid()) {
+ rectangle->setPenColor(d->pen->color());
+ rectangle->setPenWidth(d->pen->width());
+ } else {
+ rectangle->setPenColor(QColor());
+ rectangle->setPenWidth(0);
+ }
+
+ rectangle->setRadius(d->radius);
+
+ QGradientStops stops;
+ if (d->gradient) {
+ QList<QSGGradientStop *> qxstops = d->gradient->m_stops;
+ for (int i = 0; i < qxstops.size(); ++i)
+ stops.append(QGradientStop(qxstops.at(i)->position(), qxstops.at(i)->color()));
+ }
+ rectangle->setGradientStops(stops);
+
+ rectangle->update();
+
+ return rectangle;
+}
+
+QRectF QSGRectangle::boundingRect() const
+{
+ Q_D(const QSGRectangle);
+ return QRectF(-d->paintmargin, -d->paintmargin, width()+d->paintmargin*2, height()+d->paintmargin*2);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgrectangle_p.h b/src/declarative/items/qsgrectangle_p.h
new file mode 100644
index 0000000000..6cd5172f35
--- /dev/null
+++ b/src/declarative/items/qsgrectangle_p.h
@@ -0,0 +1,184 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGRECTANGLE_P_H
+#define QSGRECTANGLE_P_H
+
+#include "qsgitem.h"
+
+#include <QtGui/qbrush.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGPen : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int width READ width WRITE setWidth NOTIFY penChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY penChanged)
+public:
+ QSGPen(QObject *parent=0);
+
+ int width() const;
+ void setWidth(int w);
+
+ QColor color() const;
+ void setColor(const QColor &c);
+
+ bool isValid() const;
+
+Q_SIGNALS:
+ void penChanged();
+
+private:
+ int _width;
+ QColor _color;
+ bool _valid;
+};
+
+class Q_AUTOTEST_EXPORT QSGGradientStop : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal position READ position WRITE setPosition)
+ Q_PROPERTY(QColor color READ color WRITE setColor)
+
+public:
+ QSGGradientStop(QObject *parent=0);
+
+ qreal position() const;
+ void setPosition(qreal position);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+private:
+ void updateGradient();
+
+private:
+ qreal m_position;
+ QColor m_color;
+};
+
+class Q_AUTOTEST_EXPORT QSGGradient : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativeListProperty<QSGGradientStop> stops READ stops)
+ Q_CLASSINFO("DefaultProperty", "stops")
+
+public:
+ QSGGradient(QObject *parent=0);
+ ~QSGGradient();
+
+ QDeclarativeListProperty<QSGGradientStop> stops();
+
+ const QGradient *gradient() const;
+
+Q_SIGNALS:
+ void updated();
+
+private:
+ void doUpdate();
+
+private:
+ QList<QSGGradientStop *> m_stops;
+ mutable QGradient *m_gradient;
+ friend class QSGRectangle;
+ friend class QSGGradientStop;
+};
+
+class QSGRectanglePrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGRectangle : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QSGGradient *gradient READ gradient WRITE setGradient)
+ Q_PROPERTY(QSGPen * border READ border CONSTANT)
+ Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
+public:
+ QSGRectangle(QSGItem *parent=0);
+
+ QColor color() const;
+ void setColor(const QColor &);
+
+ QSGPen *border();
+
+ QSGGradient *gradient() const;
+ void setGradient(QSGGradient *gradient);
+
+ qreal radius() const;
+ void setRadius(qreal radius);
+
+ QRectF boundingRect() const;
+
+Q_SIGNALS:
+ void colorChanged();
+ void radiusChanged();
+
+protected:
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private Q_SLOTS:
+ void doUpdate();
+
+private:
+ Q_DISABLE_COPY(QSGRectangle)
+ Q_DECLARE_PRIVATE(QSGRectangle)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGPen)
+QML_DECLARE_TYPE(QSGGradientStop)
+QML_DECLARE_TYPE(QSGGradient)
+QML_DECLARE_TYPE(QSGRectangle)
+
+QT_END_HEADER
+
+#endif // QSGRECTANGLE_P_H
diff --git a/src/declarative/items/qsgrectangle_p_p.h b/src/declarative/items/qsgrectangle_p_p.h
new file mode 100644
index 0000000000..15bbd1f032
--- /dev/null
+++ b/src/declarative/items/qsgrectangle_p_p.h
@@ -0,0 +1,109 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGRECTANGLE_P_P_H
+#define QSGRECTANGLE_P_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 "qsgitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGGradient;
+class QSGRectangle;
+class QSGRectanglePrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGRectangle)
+
+public:
+ QSGRectanglePrivate() :
+ color(Qt::white), gradient(0), pen(0), radius(0), paintmargin(0)
+ {
+ }
+
+ ~QSGRectanglePrivate()
+ {
+ delete pen;
+ }
+
+ QColor color;
+ QSGGradient *gradient;
+ QSGPen *pen;
+ qreal radius;
+ qreal paintmargin;
+ static int doUpdateSlotIdx;
+
+ QSGPen *getPen() {
+ if (!pen) {
+ Q_Q(QSGRectangle);
+ pen = new QSGPen;
+ static int penChangedSignalIdx = -1;
+ if (penChangedSignalIdx < 0)
+ penChangedSignalIdx = QSGPen::staticMetaObject.indexOfSignal("penChanged()");
+ if (doUpdateSlotIdx < 0)
+ doUpdateSlotIdx = QSGRectangle::staticMetaObject.indexOfSlot("doUpdate()");
+ QMetaObject::connect(pen, penChangedSignalIdx, q, doUpdateSlotIdx);
+ }
+ return pen;
+ }
+
+ void setPaintMargin(qreal margin)
+ {
+ if (margin == paintmargin)
+ return;
+ paintmargin = margin;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGRECTANGLE_P_P_H
diff --git a/src/declarative/items/qsgrepeater.cpp b/src/declarative/items/qsgrepeater.cpp
new file mode 100644
index 0000000000..ac6086fc62
--- /dev/null
+++ b/src/declarative/items/qsgrepeater.cpp
@@ -0,0 +1,294 @@
+// Commit: a9f1eaa6a368bf7a72b52c428728a3e3e0a76209
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrepeater_p.h"
+#include "qsgrepeater_p_p.h"
+#include "qsgvisualitemmodel_p.h"
+
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativelistaccessor_p.h>
+#include <private/qlistmodelinterface_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGRepeaterPrivate::QSGRepeaterPrivate()
+: model(0), ownModel(false)
+{
+}
+
+QSGRepeaterPrivate::~QSGRepeaterPrivate()
+{
+ if (ownModel)
+ delete model;
+}
+
+QSGRepeater::QSGRepeater(QSGItem *parent)
+ : QSGItem(*(new QSGRepeaterPrivate), parent)
+{
+}
+
+QSGRepeater::~QSGRepeater()
+{
+}
+
+QVariant QSGRepeater::model() const
+{
+ Q_D(const QSGRepeater);
+ return d->dataSource;
+}
+
+void QSGRepeater::setModel(const QVariant &model)
+{
+ Q_D(QSGRepeater);
+ if (d->dataSource == model)
+ return;
+
+ clear();
+ if (d->model) {
+ disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ /*
+ disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ */
+ }
+ d->dataSource = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QSGVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QSGVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ dataModel->setModel(model);
+ }
+ if (d->model) {
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
+ connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+ /*
+ connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
+ */
+ regenerate();
+ }
+ emit modelChanged();
+ emit countChanged();
+}
+
+QDeclarativeComponent *QSGRepeater::delegate() const
+{
+ Q_D(const QSGRepeater);
+ if (d->model) {
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QSGRepeater::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QSGRepeater);
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
+ if (delegate == dataModel->delegate())
+ return;
+
+ if (!d->ownModel) {
+ d->model = new QSGVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model)) {
+ dataModel->setDelegate(delegate);
+ regenerate();
+ emit delegateChanged();
+ }
+}
+
+int QSGRepeater::count() const
+{
+ Q_D(const QSGRepeater);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+QSGItem *QSGRepeater::itemAt(int index) const
+{
+ Q_D(const QSGRepeater);
+ if (index >= 0 && index < d->deletables.count())
+ return d->deletables[index];
+ return 0;
+}
+
+void QSGRepeater::componentComplete()
+{
+ QSGItem::componentComplete();
+ regenerate();
+}
+
+void QSGRepeater::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ QSGItem::itemChange(change, value);
+ if (change == ItemParentHasChanged) {
+ regenerate();
+ }
+}
+
+void QSGRepeater::clear()
+{
+ Q_D(QSGRepeater);
+ bool complete = isComponentComplete();
+
+ if (d->model) {
+ while (d->deletables.count() > 0) {
+ QSGItem *item = d->deletables.takeLast();
+ if (complete)
+ emit itemRemoved(d->deletables.count()-1, item);
+ d->model->release(item);
+ }
+ }
+ d->deletables.clear();
+}
+
+void QSGRepeater::regenerate()
+{
+ Q_D(QSGRepeater);
+ if (!isComponentComplete())
+ return;
+
+ clear();
+
+ if (!d->model || !d->model->count() || !d->model->isValid() || !parentItem() || !isComponentComplete())
+ return;
+
+ for (int ii = 0; ii < count(); ++ii) {
+ QSGItem *item = d->model->item(ii);
+ if (item) {
+ QDeclarative_setParent_noEvent(item, parentItem());
+ item->setParentItem(parentItem());
+ item->stackBefore(this);
+ d->deletables << item;
+ emit itemAdded(ii, item);
+ }
+ }
+}
+
+void QSGRepeater::itemsInserted(int index, int count)
+{
+ Q_D(QSGRepeater);
+ if (!isComponentComplete())
+ return;
+ for (int i = 0; i < count; ++i) {
+ int modelIndex = index + i;
+ QSGItem *item = d->model->item(modelIndex);
+ if (item) {
+ QDeclarative_setParent_noEvent(item, parentItem());
+ item->setParentItem(parentItem());
+ if (modelIndex < d->deletables.count())
+ item->stackBefore(d->deletables.at(modelIndex));
+ else
+ item->stackBefore(this);
+ d->deletables.insert(modelIndex, item);
+ emit itemAdded(modelIndex, item);
+ }
+ }
+ emit countChanged();
+}
+
+void QSGRepeater::itemsRemoved(int index, int count)
+{
+ Q_D(QSGRepeater);
+ if (!isComponentComplete() || count <= 0)
+ return;
+ while (count--) {
+ QSGItem *item = d->deletables.takeAt(index);
+ emit itemRemoved(index, item);
+ if (item)
+ d->model->release(item);
+ else
+ break;
+ }
+ emit countChanged();
+}
+
+void QSGRepeater::itemsMoved(int from, int to, int count)
+{
+ Q_D(QSGRepeater);
+ if (!isComponentComplete() || count <= 0)
+ return;
+ if (from + count > d->deletables.count()) {
+ regenerate();
+ return;
+ }
+ QList<QSGItem*> removed;
+ int removedCount = count;
+ while (removedCount--)
+ removed << d->deletables.takeAt(from);
+ for (int i = 0; i < count; ++i)
+ d->deletables.insert(to + i, removed.at(i));
+ d->deletables.last()->stackBefore(this);
+ for (int i = d->model->count()-1; i > 0; --i) {
+ QSGItem *item = d->deletables.at(i-1);
+ item->stackBefore(d->deletables.at(i));
+ }
+}
+
+void QSGRepeater::modelReset()
+{
+ if (!isComponentComplete())
+ return;
+ regenerate();
+ emit countChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgrepeater_p.h b/src/declarative/items/qsgrepeater_p.h
new file mode 100644
index 0000000000..3a53fa4177
--- /dev/null
+++ b/src/declarative/items/qsgrepeater_p.h
@@ -0,0 +1,111 @@
+// Commit: ebd4bc73c46c2962742a682b6a391fb68c482aec
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGREPEATER_P_H
+#define QSGREPEATER_P_H
+
+#include "qsgitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGRepeaterPrivate;
+class Q_AUTOTEST_EXPORT QSGRepeater : public QSGItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_CLASSINFO("DefaultProperty", "delegate")
+
+public:
+ QSGRepeater(QSGItem *parent=0);
+ virtual ~QSGRepeater();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int count() const;
+
+ Q_INVOKABLE QSGItem *itemAt(int index) const;
+
+Q_SIGNALS:
+ void modelChanged();
+ void delegateChanged();
+ void countChanged();
+
+ void itemAdded(int index, QSGItem *item);
+ void itemRemoved(int index, QSGItem *item);
+
+private:
+ void clear();
+ void regenerate();
+
+protected:
+ virtual void componentComplete();
+ void itemChange(ItemChange change, const ItemChangeData &value);
+
+private Q_SLOTS:
+ void itemsInserted(int,int);
+ void itemsRemoved(int,int);
+ void itemsMoved(int,int,int);
+ void modelReset();
+
+private:
+ Q_DISABLE_COPY(QSGRepeater)
+ Q_DECLARE_PRIVATE(QSGRepeater)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGRepeater)
+
+QT_END_HEADER
+
+#endif // QSGREPEATER_P_H
diff --git a/src/declarative/items/qsgrepeater_p_p.h b/src/declarative/items/qsgrepeater_p_p.h
new file mode 100644
index 0000000000..155f1b8c6d
--- /dev/null
+++ b/src/declarative/items/qsgrepeater_p_p.h
@@ -0,0 +1,83 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGREPEATER_P_P_H
+#define QSGREPEATER_P_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 "qsgrepeater_p.h"
+#include "qsgitem_p.h"
+
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContext;
+class QSGVisualModel;
+class QSGRepeaterPrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGRepeater)
+
+public:
+ QSGRepeaterPrivate();
+ ~QSGRepeaterPrivate();
+
+ QSGVisualModel *model;
+ QVariant dataSource;
+ bool ownModel;
+
+ QList<QPointer<QSGItem> > deletables;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGREPEATER_P_P_H
diff --git a/src/declarative/items/qsgscalegrid.cpp b/src/declarative/items/qsgscalegrid.cpp
new file mode 100644
index 0000000000..4a73801159
--- /dev/null
+++ b/src/declarative/items/qsgscalegrid.cpp
@@ -0,0 +1,213 @@
+// Commit: 7ddec9f3179bfd854ae53e23ab292de1f9a26377
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgscalegrid_p_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QSGScaleGrid
+ \brief The QSGScaleGrid class allows you to specify a 3x3 grid to use in scaling an image.
+*/
+
+QSGScaleGrid::QSGScaleGrid(QObject *parent) : QObject(parent), _left(0), _top(0), _right(0), _bottom(0)
+{
+}
+
+QSGScaleGrid::~QSGScaleGrid()
+{
+}
+
+bool QSGScaleGrid::isNull() const
+{
+ return !_left && !_top && !_right && !_bottom;
+}
+
+void QSGScaleGrid::setLeft(int pos)
+{
+ if (_left != pos) {
+ _left = pos;
+ emit borderChanged();
+ }
+}
+
+void QSGScaleGrid::setTop(int pos)
+{
+ if (_top != pos) {
+ _top = pos;
+ emit borderChanged();
+ }
+}
+
+void QSGScaleGrid::setRight(int pos)
+{
+ if (_right != pos) {
+ _right = pos;
+ emit borderChanged();
+ }
+}
+
+void QSGScaleGrid::setBottom(int pos)
+{
+ if (_bottom != pos) {
+ _bottom = pos;
+ emit borderChanged();
+ }
+}
+
+QSGGridScaledImage::QSGGridScaledImage()
+: _l(-1), _r(-1), _t(-1), _b(-1),
+ _h(QSGBorderImage::Stretch), _v(QSGBorderImage::Stretch)
+{
+}
+
+QSGGridScaledImage::QSGGridScaledImage(const QSGGridScaledImage &o)
+: _l(o._l), _r(o._r), _t(o._t), _b(o._b), _h(o._h), _v(o._v), _pix(o._pix)
+{
+}
+
+QSGGridScaledImage &QSGGridScaledImage::operator=(const QSGGridScaledImage &o)
+{
+ _l = o._l;
+ _r = o._r;
+ _t = o._t;
+ _b = o._b;
+ _h = o._h;
+ _v = o._v;
+ _pix = o._pix;
+ return *this;
+}
+
+QSGGridScaledImage::QSGGridScaledImage(QIODevice *data)
+: _l(-1), _r(-1), _t(-1), _b(-1), _h(QSGBorderImage::Stretch), _v(QSGBorderImage::Stretch)
+{
+ int l = -1;
+ int r = -1;
+ int t = -1;
+ int b = -1;
+ QString imgFile;
+
+ QByteArray raw;
+ while(raw = data->readLine(), !raw.isEmpty()) {
+ QString line = QString::fromUtf8(raw.trimmed());
+ if (line.isEmpty() || line.startsWith(QLatin1Char('#')))
+ continue;
+
+ int colonId = line.indexOf(QLatin1Char(':'));
+ if (colonId <= 0)
+ return;
+
+ QStringList list;
+ list.append(line.left(colonId).trimmed());
+ list.append(line.mid(colonId+1).trimmed());
+
+ if (list[0] == QLatin1String("border.left"))
+ l = list[1].toInt();
+ else if (list[0] == QLatin1String("border.right"))
+ r = list[1].toInt();
+ else if (list[0] == QLatin1String("border.top"))
+ t = list[1].toInt();
+ else if (list[0] == QLatin1String("border.bottom"))
+ b = list[1].toInt();
+ else if (list[0] == QLatin1String("source"))
+ imgFile = list[1];
+ else if (list[0] == QLatin1String("horizontalTileRule"))
+ _h = stringToRule(list[1]);
+ else if (list[0] == QLatin1String("verticalTileRule"))
+ _v = stringToRule(list[1]);
+ }
+
+ if (l < 0 || r < 0 || t < 0 || b < 0 || imgFile.isEmpty())
+ return;
+
+ _l = l; _r = r; _t = t; _b = b;
+
+ _pix = imgFile;
+}
+
+QSGBorderImage::TileMode QSGGridScaledImage::stringToRule(const QString &s)
+{
+ if (s == QLatin1String("Stretch"))
+ return QSGBorderImage::Stretch;
+ if (s == QLatin1String("Repeat"))
+ return QSGBorderImage::Repeat;
+ if (s == QLatin1String("Round"))
+ return QSGBorderImage::Round;
+
+ qWarning("QSGGridScaledImage: Invalid tile rule specified. Using Stretch.");
+ return QSGBorderImage::Stretch;
+}
+
+bool QSGGridScaledImage::isValid() const
+{
+ return _l >= 0;
+}
+
+int QSGGridScaledImage::gridLeft() const
+{
+ return _l;
+}
+
+int QSGGridScaledImage::gridRight() const
+{
+ return _r;
+}
+
+int QSGGridScaledImage::gridTop() const
+{
+ return _t;
+}
+
+int QSGGridScaledImage::gridBottom() const
+{
+ return _b;
+}
+
+QString QSGGridScaledImage::pixmapUrl() const
+{
+ return _pix;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgscalegrid_p_p.h b/src/declarative/items/qsgscalegrid_p_p.h
new file mode 100644
index 0000000000..57beb4b3b0
--- /dev/null
+++ b/src/declarative/items/qsgscalegrid_p_p.h
@@ -0,0 +1,134 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSCALEGRID_P_P_H
+#define QSGSCALEGRID_P_P_H
+
+#include "qsgborderimage_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtCore/qobject.h>
+
+#include <private/qdeclarativepixmapcache_p.h>
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGScaleGrid : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(TileRule)
+
+ Q_PROPERTY(int left READ left WRITE setLeft NOTIFY borderChanged)
+ Q_PROPERTY(int top READ top WRITE setTop NOTIFY borderChanged)
+ Q_PROPERTY(int right READ right WRITE setRight NOTIFY borderChanged)
+ Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY borderChanged)
+
+public:
+ QSGScaleGrid(QObject *parent=0);
+ ~QSGScaleGrid();
+
+ bool isNull() const;
+
+ int left() const { return _left; }
+ void setLeft(int);
+
+ int top() const { return _top; }
+ void setTop(int);
+
+ int right() const { return _right; }
+ void setRight(int);
+
+ int bottom() const { return _bottom; }
+ void setBottom(int);
+
+Q_SIGNALS:
+ void borderChanged();
+
+private:
+ int _left;
+ int _top;
+ int _right;
+ int _bottom;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGGridScaledImage
+{
+public:
+ QSGGridScaledImage();
+ QSGGridScaledImage(const QSGGridScaledImage &);
+ QSGGridScaledImage(QIODevice*);
+ QSGGridScaledImage &operator=(const QSGGridScaledImage &);
+ bool isValid() const;
+ int gridLeft() const;
+ int gridRight() const;
+ int gridTop() const;
+ int gridBottom() const;
+ QSGBorderImage::TileMode horizontalTileRule() const { return _h; }
+ QSGBorderImage::TileMode verticalTileRule() const { return _v; }
+
+ QString pixmapUrl() const;
+
+private:
+ static QSGBorderImage::TileMode stringToRule(const QString &);
+
+private:
+ int _l;
+ int _r;
+ int _t;
+ int _b;
+ QSGBorderImage::TileMode _h;
+ QSGBorderImage::TileMode _v;
+ QString _pix;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGScaleGrid)
+
+QT_END_HEADER
+
+#endif // QSGSCALEGRID_P_P_H
diff --git a/src/declarative/items/qsgshadereffectitem.cpp b/src/declarative/items/qsgshadereffectitem.cpp
new file mode 100644
index 0000000000..286b67bacd
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectitem.cpp
@@ -0,0 +1,449 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgshadereffectitem_p.h>
+#include <private/qsgshadereffectnode_p.h>
+
+#include "qsgmaterial.h"
+#include "qsgitem_p.h"
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgtextureprovider_p.h>
+#include "qsgcanvas.h"
+
+#include <QtCore/qsignalmapper.h>
+#include <QtOpenGL/qglframebufferobject.h>
+
+QT_BEGIN_NAMESPACE
+
+static const char qt_default_vertex_code[] =
+ "uniform highp mat4 qt_ModelViewProjectionMatrix; \n"
+ "attribute highp vec4 qt_Vertex; \n"
+ "attribute highp vec2 qt_MultiTexCoord0; \n"
+ "varying highp vec2 qt_TexCoord0; \n"
+ "void main() { \n"
+ " qt_TexCoord0 = qt_MultiTexCoord0; \n"
+ " gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex; \n"
+ "}";
+
+static const char qt_default_fragment_code[] =
+ "varying highp vec2 qt_TexCoord0; \n"
+ "uniform sampler2D source; \n"
+ "uniform lowp float qt_Opacity; \n"
+ "void main() { \n"
+ " gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity; \n"
+ "}";
+
+static const char qt_position_attribute_name[] = "qt_Vertex";
+static const char qt_texcoord_attribute_name[] = "qt_MultiTexCoord0";
+
+const char *qtPositionAttributeName()
+{
+ return qt_position_attribute_name;
+}
+
+const char *qtTexCoordAttributeName()
+{
+ return qt_texcoord_attribute_name;
+}
+
+QSGShaderEffectItem::QSGShaderEffectItem(QSGItem *parent)
+ : QSGItem(parent)
+ , m_mesh(0)
+ , m_cullMode(NoCulling)
+ , m_blending(true)
+ , m_dirtyData(true)
+ , m_programDirty(true)
+ , m_dirtyMesh(true)
+ , m_dirtyGeometry(true)
+{
+ setFlag(QSGItem::ItemHasContents);
+}
+
+QSGShaderEffectItem::~QSGShaderEffectItem()
+{
+ reset();
+}
+
+void QSGShaderEffectItem::componentComplete()
+{
+ updateProperties();
+ QSGItem::componentComplete();
+}
+
+void QSGShaderEffectItem::setFragmentShader(const QByteArray &code)
+{
+ if (m_source.fragmentCode.constData() == code.constData())
+ return;
+ m_source.fragmentCode = code;
+ if (isComponentComplete()) {
+ reset();
+ updateProperties();
+ }
+ emit fragmentShaderChanged();
+}
+
+void QSGShaderEffectItem::setVertexShader(const QByteArray &code)
+{
+ if (m_source.vertexCode.constData() == code.constData())
+ return;
+ m_source.vertexCode = code;
+ if (isComponentComplete()) {
+ reset();
+ updateProperties();
+ }
+ emit vertexShaderChanged();
+}
+
+void QSGShaderEffectItem::setBlending(bool enable)
+{
+ if (blending() == enable)
+ return;
+
+ m_blending = enable;
+ update();
+
+ emit blendingChanged();
+}
+
+void QSGShaderEffectItem::setMesh(QSGShaderEffectMesh *mesh)
+{
+ if (mesh == m_mesh)
+ return;
+ if (m_mesh)
+ disconnect(m_mesh, SIGNAL(geometryChanged()), this, 0);
+ m_mesh = mesh;
+ if (m_mesh)
+ connect(m_mesh, SIGNAL(geometryChanged()), this, SLOT(updateGeometry()));
+ m_dirtyMesh = true;
+ update();
+ emit meshChanged();
+}
+
+void QSGShaderEffectItem::setCullMode(CullMode face)
+{
+ if (face == m_cullMode)
+ return;
+ m_cullMode = face;
+ update();
+ emit cullModeChanged();
+}
+
+void QSGShaderEffectItem::changeSource(int index)
+{
+ Q_ASSERT(index >= 0 && index < m_sources.size());
+ QVariant v = property(m_sources.at(index).name.constData());
+ setSource(v, index);
+}
+
+void QSGShaderEffectItem::updateData()
+{
+ m_dirtyData = true;
+ update();
+}
+
+void QSGShaderEffectItem::updateGeometry()
+{
+ m_dirtyGeometry = true;
+ update();
+}
+
+void QSGShaderEffectItem::setSource(const QVariant &var, int index)
+{
+ Q_ASSERT(index >= 0 && index < m_sources.size());
+
+ SourceData &source = m_sources[index];
+
+ source.item = 0;
+ if (var.isNull()) {
+ return;
+ } else if (!qVariantCanConvert<QObject *>(var)) {
+ qWarning("Could not assign source of type '%s' to property '%s'.", var.typeName(), source.name.constData());
+ return;
+ }
+
+ QObject *obj = qVariantValue<QObject *>(var);
+
+ QSGTextureProvider *int3rface = QSGTextureProvider::from(obj);
+ if (!int3rface) {
+ qWarning("Could not assign property '%s', did not implement QSGTextureProvider.", source.name.constData());
+ }
+
+ source.item = qobject_cast<QSGItem *>(obj);
+
+ // TODO: Find better solution.
+ // 'source.item' needs a canvas to get a scenegraph node.
+ // The easiest way to make sure it gets a canvas is to
+ // make it a part of the same item tree as 'this'.
+ if (source.item && source.item->parentItem() == 0) {
+ source.item->setParentItem(this);
+ source.item->setVisible(false);
+ }
+}
+
+void QSGShaderEffectItem::disconnectPropertySignals()
+{
+ disconnect(this, 0, this, SLOT(updateData()));
+ for (int i = 0; i < m_sources.size(); ++i) {
+ SourceData &source = m_sources[i];
+ disconnect(this, 0, source.mapper, 0);
+ disconnect(source.mapper, 0, this, 0);
+ }
+}
+
+void QSGShaderEffectItem::connectPropertySignals()
+{
+ QSet<QByteArray>::const_iterator it;
+ for (it = m_source.uniformNames.begin(); it != m_source.uniformNames.end(); ++it) {
+ int pi = metaObject()->indexOfProperty(it->constData());
+ if (pi >= 0) {
+ QMetaProperty mp = metaObject()->property(pi);
+ if (!mp.hasNotifySignal())
+ qWarning("QSGShaderEffectItem: property '%s' does not have notification method!", it->constData());
+ QByteArray signalName("2");
+ signalName.append(mp.notifySignal().signature());
+ connect(this, signalName, this, SLOT(updateData()));
+ } else {
+ qWarning("QSGShaderEffectItem: '%s' does not have a matching property!", it->constData());
+ }
+ }
+ for (int i = 0; i < m_sources.size(); ++i) {
+ SourceData &source = m_sources[i];
+ int pi = metaObject()->indexOfProperty(source.name.constData());
+ if (pi >= 0) {
+ QMetaProperty mp = metaObject()->property(pi);
+ QByteArray signalName("2");
+ signalName.append(mp.notifySignal().signature());
+ connect(this, signalName, source.mapper, SLOT(map()));
+ source.mapper->setMapping(this, i);
+ connect(source.mapper, SIGNAL(mapped(int)), this, SLOT(changeSource(int)));
+ } else {
+ qWarning("QSGShaderEffectItem: '%s' does not have a matching source!", source.name.constData());
+ }
+ }
+}
+
+void QSGShaderEffectItem::reset()
+{
+ disconnectPropertySignals();
+
+ m_source.attributeNames.clear();
+ m_source.uniformNames.clear();
+ m_source.respectsOpacity = false;
+ m_source.respectsMatrix = false;
+ m_source.className = metaObject()->className();
+
+ for (int i = 0; i < m_sources.size(); ++i) {
+ const SourceData &source = m_sources.at(i);
+ delete source.mapper;
+ if (source.item && source.item->parentItem() == this)
+ source.item->setParentItem(0);
+ }
+ m_sources.clear();
+
+ m_programDirty = true;
+ m_dirtyMesh = true;
+}
+
+void QSGShaderEffectItem::updateProperties()
+{
+ QByteArray vertexCode = m_source.vertexCode;
+ QByteArray fragmentCode = m_source.fragmentCode;
+ if (vertexCode.isEmpty())
+ vertexCode = qt_default_vertex_code;
+ if (fragmentCode.isEmpty())
+ fragmentCode = qt_default_fragment_code;
+
+ lookThroughShaderCode(vertexCode);
+ lookThroughShaderCode(fragmentCode);
+
+ if (!m_mesh && !m_source.attributeNames.contains(qt_position_attribute_name))
+ qWarning("QSGShaderEffectItem: Missing reference to \'%s\'.", qt_position_attribute_name);
+ if (!m_mesh && !m_source.attributeNames.contains(qt_texcoord_attribute_name))
+ qWarning("QSGShaderEffectItem: Missing reference to \'%s\'.", qt_texcoord_attribute_name);
+ if (!m_source.respectsMatrix)
+ qWarning("QSGShaderEffectItem: Missing reference to \'qt_ModelViewProjectionMatrix\'.");
+ if (!m_source.respectsOpacity)
+ qWarning("QSGShaderEffectItem: Missing reference to \'qt_Opacity\'.");
+
+ for (int i = 0; i < m_sources.size(); ++i) {
+ QVariant v = property(m_sources.at(i).name);
+ setSource(v, i);
+ }
+
+ connectPropertySignals();
+}
+
+void QSGShaderEffectItem::lookThroughShaderCode(const QByteArray &code)
+{
+ // Regexp for matching attributes and uniforms.
+ // In human readable form: attribute|uniform [lowp|mediump|highp] <type> <name>
+ static QRegExp re(QLatin1String("\\b(attribute|uniform)\\b\\s*\\b(?:lowp|mediump|highp)?\\b\\s*\\b(\\w+)\\b\\s*\\b(\\w+)"));
+ Q_ASSERT(re.isValid());
+
+ int pos = -1;
+
+ QString wideCode = QString::fromLatin1(code.constData(), code.size());
+
+ while ((pos = re.indexIn(wideCode, pos + 1)) != -1) {
+ QByteArray decl = re.cap(1).toLatin1(); // uniform or attribute
+ QByteArray type = re.cap(2).toLatin1(); // type
+ QByteArray name = re.cap(3).toLatin1(); // variable name
+
+ if (decl == "attribute") {
+ m_source.attributeNames.append(name);
+ } else {
+ Q_ASSERT(decl == "uniform");
+
+ if (name == "qt_ModelViewProjectionMatrix") {
+ m_source.respectsMatrix = true;
+ } else if (name == "qt_Opacity") {
+ m_source.respectsOpacity = true;
+ } else {
+ m_source.uniformNames.insert(name);
+ if (type == "sampler2D") {
+ SourceData d;
+ d.mapper = new QSignalMapper;
+ d.name = name;
+ d.item = 0;
+ m_sources.append(d);
+ }
+ }
+ }
+ }
+}
+
+void QSGShaderEffectItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ m_dirtyGeometry = true;
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+QSGNode *QSGShaderEffectItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ QSGShaderEffectNode *node = static_cast<QSGShaderEffectNode *>(oldNode);
+
+ if (!node) {
+ node = new QSGShaderEffectNode;
+ node->setMaterial(&m_material);
+ m_programDirty = true;
+ m_dirtyData = true;
+ m_dirtyGeometry = true;
+ }
+
+ if (m_dirtyMesh) {
+ node->setGeometry(0);
+ m_dirtyMesh = false;
+ m_dirtyGeometry = true;
+ }
+
+ if (m_dirtyGeometry) {
+ node->setFlag(QSGNode::OwnsGeometry, false);
+ QSGGeometry *geometry = node->geometry();
+ QRectF rect(0, 0, width(), height());
+ QSGShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
+
+ geometry = mesh->updateGeometry(geometry, m_source.attributeNames, rect);
+ if (!geometry) {
+ delete node;
+ return 0;
+ }
+
+ node->setGeometry(geometry);
+ node->setFlag(QSGNode::OwnsGeometry, true);
+
+ m_dirtyGeometry = false;
+ }
+
+ if (m_programDirty) {
+ QSGShaderEffectProgram s = m_source;
+ if (s.fragmentCode.isEmpty())
+ s.fragmentCode = qt_default_fragment_code;
+ if (s.vertexCode.isEmpty())
+ s.vertexCode = qt_default_vertex_code;
+
+ m_material.setProgramSource(s);
+ node->markDirty(QSGNode::DirtyMaterial);
+ m_programDirty = false;
+ }
+
+ // Update blending
+ if (bool(m_material.flags() & QSGMaterial::Blending) != m_blending) {
+ m_material.setFlag(QSGMaterial::Blending, m_blending);
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (int(m_material.cullMode()) != int(m_cullMode)) {
+ m_material.setCullMode(QSGShaderEffectMaterial::CullMode(m_cullMode));
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (m_dirtyData) {
+ QVector<QPair<QByteArray, QVariant> > values;
+ QVector<QPair<QByteArray, QPointer<QSGItem> > > textures;
+ const QVector<QPair<QByteArray, QPointer<QSGItem> > > &oldTextures = m_material.textureProviders();
+
+ for (QSet<QByteArray>::const_iterator it = m_source.uniformNames.begin();
+ it != m_source.uniformNames.end(); ++it) {
+ values.append(qMakePair(*it, property(*it)));
+ }
+ for (int i = 0; i < oldTextures.size(); ++i) {
+ QSGTextureProvider *oldSource = QSGTextureProvider::from(oldTextures.at(i).second);
+ if (oldSource && oldSource->textureChangedSignal())
+ disconnect(oldTextures.at(i).second, oldSource->textureChangedSignal(), node, SLOT(markDirtyTexture()));
+ }
+ for (int i = 0; i < m_sources.size(); ++i) {
+ const SourceData &source = m_sources.at(i);
+ textures.append(qMakePair(source.name, source.item));
+ QSGTextureProvider *t = QSGTextureProvider::from(source.item);
+ if (t && t->textureChangedSignal())
+ connect(source.item, t->textureChangedSignal(), node, SLOT(markDirtyTexture()));
+ }
+ m_material.setUniforms(values);
+ m_material.setTextureProviders(textures);
+ node->markDirty(QSGNode::DirtyMaterial);
+ m_dirtyData = false;
+ }
+
+ return node;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgshadereffectitem_p.h b/src/declarative/items/qsgshadereffectitem_p.h
new file mode 100644
index 0000000000..84f80492aa
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectitem_p.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SHADEREFFECTITEM_H
+#define SHADEREFFECTITEM_H
+
+#include "qsgitem.h"
+
+#include "qsgmaterial.h"
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgshadereffectnode_p.h>
+#include "qsgshadereffectmesh_p.h"
+
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+const char *qtPositionAttributeName();
+const char *qtTexCoordAttributeName();
+
+class QSGContext;
+class QSignalMapper;
+class QSGCustomMaterialShader;
+
+class QSGShaderEffectItem : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QByteArray fragmentShader READ fragmentShader WRITE setFragmentShader NOTIFY fragmentShaderChanged)
+ Q_PROPERTY(QByteArray vertexShader READ vertexShader WRITE setVertexShader NOTIFY vertexShaderChanged)
+ Q_PROPERTY(bool blending READ blending WRITE setBlending NOTIFY blendingChanged)
+ Q_PROPERTY(QSGShaderEffectMesh *mesh READ mesh WRITE setMesh NOTIFY meshChanged)
+ Q_PROPERTY(CullMode culling READ cullMode WRITE setCullMode NOTIFY cullModeChanged)
+ Q_ENUMS(CullMode)
+
+public:
+ enum CullMode
+ {
+ NoCulling = QSGShaderEffectMaterial::NoCulling,
+ BackFaceCulling = QSGShaderEffectMaterial::BackFaceCulling,
+ FrontFaceCulling = QSGShaderEffectMaterial::FrontFaceCulling
+ };
+
+ QSGShaderEffectItem(QSGItem *parent = 0);
+ ~QSGShaderEffectItem();
+
+ virtual void componentComplete();
+
+ QByteArray fragmentShader() const { return m_source.fragmentCode; }
+ void setFragmentShader(const QByteArray &code);
+
+ QByteArray vertexShader() const { return m_source.vertexCode; }
+ void setVertexShader(const QByteArray &code);
+
+ bool blending() const { return m_blending; }
+ void setBlending(bool enable);
+
+ QSGShaderEffectMesh *mesh() const { return m_mesh; }
+ void setMesh(QSGShaderEffectMesh *mesh);
+
+ CullMode cullMode() const { return m_cullMode; }
+ void setCullMode(CullMode face);
+
+Q_SIGNALS:
+ void fragmentShaderChanged();
+ void vertexShaderChanged();
+ void blendingChanged();
+ void marginsChanged();
+ void meshChanged();
+ void cullModeChanged();
+
+protected:
+ virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private Q_SLOTS:
+ void changeSource(int index);
+ void updateData();
+ void updateGeometry();
+
+private:
+ friend class QSGCustomMaterialShader;
+ friend class QSGShaderEffectNode;
+
+ void setSource(const QVariant &var, int index);
+ void disconnectPropertySignals();
+ void connectPropertySignals();
+ void reset();
+ void updateProperties();
+ void lookThroughShaderCode(const QByteArray &code);
+
+ QSGShaderEffectProgram m_source;
+ QSGShaderEffectMesh *m_mesh;
+ QSGGridMesh m_defaultMesh;
+ CullMode m_cullMode;
+
+ struct SourceData
+ {
+ QSignalMapper *mapper;
+ QPointer<QSGItem> item;
+ QByteArray name;
+ };
+ QVector<SourceData> m_sources;
+ QSGShaderEffectMaterial m_material;
+
+ uint m_blending : 1;
+ uint m_dirtyData : 1;
+
+ uint m_programDirty : 1;
+ uint m_dirtyMesh : 1;
+ uint m_dirtyGeometry : 1;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SHADEREFFECTITEM_H
diff --git a/src/declarative/items/qsgshadereffectmesh.cpp b/src/declarative/items/qsgshadereffectmesh.cpp
new file mode 100644
index 0000000000..09d820706b
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectmesh.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgshadereffectmesh_p.h"
+#include "qsggeometry.h"
+#include "qsgshadereffectitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGShaderEffectMesh::QSGShaderEffectMesh(QObject *parent)
+ : QObject(parent)
+{
+}
+
+
+QSGGridMesh::QSGGridMesh(QObject *parent)
+ : QSGShaderEffectMesh(parent)
+ , m_resolution(1, 1)
+{
+ connect(this, SIGNAL(resolutionChanged()), this, SIGNAL(geometryChanged()));
+}
+
+QSGGeometry *QSGGridMesh::updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &dstRect) const
+{
+ int vmesh = m_resolution.height();
+ int hmesh = m_resolution.width();
+ int attrCount = attributes.count();
+
+ if (!geometry) {
+ bool error = true;
+ switch (attrCount) {
+ case 0:
+ qWarning("QSGGridMesh:: No attributes specified.");
+ break;
+ case 1:
+ if (attributes.at(0) == qtPositionAttributeName()) {
+ error = false;
+ break;
+ }
+ qWarning("QSGGridMesh:: Missing \'%s\' attribute.",
+ qtPositionAttributeName());
+ break;
+ case 2:
+ if (attributes.contains(qtPositionAttributeName())
+ && attributes.contains(qtTexCoordAttributeName()))
+ {
+ error = false;
+ break;
+ }
+ qWarning("QSGGridMesh:: Missing \'%s\' or \'%s\' attribute.",
+ qtPositionAttributeName(), qtTexCoordAttributeName());
+ break;
+ default:
+ qWarning("QSGGridMesh:: Too many attributes specified.");
+ break;;
+ }
+
+ if (error) {
+ delete geometry;
+ return 0;
+ }
+
+ geometry = new QSGGeometry(attrCount == 1
+ ? QSGGeometry::defaultAttributes_Point2D()
+ : QSGGeometry::defaultAttributes_TexturedPoint2D(),
+ (vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2),
+ GL_UNSIGNED_SHORT);
+
+ } else {
+ geometry->allocate((vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2));
+ }
+
+ QSGGeometry::Point2D *vdata = static_cast<QSGGeometry::Point2D *>(geometry->vertexData());
+
+ bool positionFirst = attributes.at(0) == qtPositionAttributeName();
+
+ QRectF srcRect(0, 1, 1, -1);
+ for (int iy = 0; iy <= vmesh; ++iy) {
+ float fy = iy / float(vmesh);
+ float y = float(dstRect.top()) + fy * float(dstRect.height());
+ float ty = float(srcRect.top()) + fy * float(srcRect.height());
+ for (int ix = 0; ix <= hmesh; ++ix) {
+ float fx = ix / float(hmesh);
+ for (int ia = 0; ia < attrCount; ++ia) {
+ if (positionFirst == (ia == 0)) {
+ vdata->x = float(dstRect.left()) + fx * float(dstRect.width());
+ vdata->y = y;
+ ++vdata;
+ } else {
+ vdata->x = float(srcRect.left()) + fx * float(srcRect.width());
+ vdata->y = ty;
+ ++vdata;
+ }
+ }
+ }
+ }
+
+ quint16 *indices = (quint16 *)geometry->indexDataAsUShort();
+ int i = 0;
+ for (int iy = 0; iy < vmesh; ++iy) {
+ *(indices++) = i + hmesh + 1;
+ for (int ix = 0; ix <= hmesh; ++ix, ++i) {
+ *(indices++) = i + hmesh + 1;
+ *(indices++) = i;
+ }
+ *(indices++) = i - 1;
+ }
+
+ return geometry;
+}
+
+void QSGGridMesh::setResolution(const QSize &res)
+{
+ if (res == m_resolution)
+ return;
+ if (res.width() < 1 || res.height() < 1) {
+ qWarning("QSGGridMesh: Resolution must be at least 1x1");
+ return;
+ }
+ m_resolution = res;
+ emit resolutionChanged();
+}
+
+QSize QSGGridMesh::resolution() const
+{
+ return m_resolution;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgshadereffectmesh_p.h b/src/declarative/items/qsgshadereffectmesh_p.h
new file mode 100644
index 0000000000..88198b5c40
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectmesh_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativeparserstatus.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qvariant.h>
+#include <QtOpenGL/qglfunctions.h>
+
+#ifndef SHADEREFFECTMESH_H
+#define SHADEREFFECTMESH_H
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGGeometry;
+class QRectF;
+
+class QSGShaderEffectMesh : public QObject
+{
+ Q_OBJECT
+public:
+ QSGShaderEffectMesh(QObject *parent = 0);
+ // If 'geometry' != 0, 'attributes' is the same as last time the function was called.
+ virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &rect) const = 0;
+
+Q_SIGNALS:
+ // Emitted when the geometry needs to be updated.
+ void geometryChanged();
+};
+
+class QSGGridMesh : public QSGShaderEffectMesh
+{
+ Q_OBJECT
+ Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged)
+public:
+ QSGGridMesh(QObject *parent = 0);
+ virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &rect) const;
+
+ void setResolution(const QSize &res);
+ QSize resolution() const;
+
+Q_SIGNALS:
+ void resolutionChanged();
+
+private:
+ QSize m_resolution;
+};
+
+inline QColor qt_premultiply_color(const QColor &c)
+{
+ return QColor::fromRgbF(c.redF() * c.alphaF(), c.greenF() * c.alphaF(), c.blueF() * c.alphaF(), c.alphaF());
+}
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SHADEREFFECTITEM_H
diff --git a/src/declarative/items/qsgshadereffectnode.cpp b/src/declarative/items/qsgshadereffectnode.cpp
new file mode 100644
index 0000000000..d1c8fbca9e
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectnode.cpp
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgshadereffectnode_p.h>
+
+#include "qsgshadereffectmesh_p.h"
+#include <private/qsgtextureprovider_p.h>
+#include <private/qsgrenderer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGCustomMaterialShader : public QSGMaterialShader
+{
+public:
+ QSGCustomMaterialShader(const QSGShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes);
+ virtual void deactivate();
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+protected:
+ friend class QSGShaderEffectNode;
+
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ const QSGShaderEffectMaterialKey m_key;
+ QVector<const char *> m_attributeNames;
+ const QVector<QByteArray> m_attributes;
+
+ QVector<int> m_uniformLocs;
+ int m_opacityLoc;
+ int m_matrixLoc;
+ uint m_textureIndicesSet;
+};
+
+QSGCustomMaterialShader::QSGCustomMaterialShader(const QSGShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes)
+ : m_key(key)
+ , m_attributes(attributes)
+ , m_textureIndicesSet(false)
+{
+ for (int i = 0; i < attributes.count(); ++i)
+ m_attributeNames.append(attributes.at(i).constData());
+ m_attributeNames.append(0);
+}
+
+void QSGCustomMaterialShader::deactivate()
+{
+ glDisable(GL_CULL_FACE);
+}
+
+void QSGCustomMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(newEffect != 0);
+
+ const QSGShaderEffectMaterial *material = static_cast<const QSGShaderEffectMaterial *>(newEffect);
+
+ if (!m_textureIndicesSet) {
+ for (int i = 0; i < material->m_textures.size(); ++i)
+ m_program.setUniformValue(material->m_textures.at(i).first.constData(), i);
+ m_textureIndicesSet = true;
+ }
+
+ if (m_uniformLocs.size() != material->m_uniformValues.size()) {
+ m_uniformLocs.reserve(material->m_uniformValues.size());
+ for (int i = 0; i < material->m_uniformValues.size(); ++i) {
+ const QByteArray &name = material->m_uniformValues.at(i).first;
+ m_uniformLocs.append(m_program.uniformLocation(name.constData()));
+ }
+ }
+
+ QGLFunctions *functions = state.context()->functions();
+ for (int i = material->m_textures.size() - 1; i >= 0; --i) {
+ QPointer<QSGItem> source = material->m_textures.at(i).second;
+ QSGTextureProvider *provider = QSGTextureProvider::from(source);
+ QSGTexture *texture = provider ? provider->texture() : 0;
+ if (!source || !provider || !texture) {
+ qWarning("ShaderEffectItem: source or provider missing when binding textures");
+ continue;
+ }
+ functions->glActiveTexture(GL_TEXTURE0 + i);
+ provider->texture()->bind();
+ }
+
+ if (material->m_source.respectsOpacity)
+ m_program.setUniformValue(m_opacityLoc, state.opacity());
+
+ for (int i = 0; i < material->m_uniformValues.count(); ++i) {
+ const QVariant &v = material->m_uniformValues.at(i).second;
+
+ switch (v.type()) {
+ case QVariant::Color:
+ m_program.setUniformValue(m_uniformLocs.at(i), qt_premultiply_color(qvariant_cast<QColor>(v)));
+ break;
+ case QVariant::Double:
+ m_program.setUniformValue(m_uniformLocs.at(i), (float) qvariant_cast<double>(v));
+ break;
+ case QVariant::Transform:
+ m_program.setUniformValue(m_uniformLocs.at(i), qvariant_cast<QTransform>(v));
+ break;
+ case QVariant::Int:
+ m_program.setUniformValue(m_uniformLocs.at(i), v.toInt());
+ break;
+ case QVariant::Bool:
+ m_program.setUniformValue(m_uniformLocs.at(i), GLint(v.toBool()));
+ break;
+ case QVariant::Size:
+ case QVariant::SizeF:
+ m_program.setUniformValue(m_uniformLocs.at(i), v.toSizeF());
+ break;
+ case QVariant::Point:
+ case QVariant::PointF:
+ m_program.setUniformValue(m_uniformLocs.at(i), v.toPointF());
+ break;
+ case QVariant::Rect:
+ case QVariant::RectF:
+ {
+ QRectF r = v.toRectF();
+ m_program.setUniformValue(m_uniformLocs.at(i), r.x(), r.y(), r.width(), r.height());
+ }
+ break;
+ case QVariant::Vector3D:
+ m_program.setUniformValue(m_uniformLocs.at(i), qvariant_cast<QVector3D>(v));
+ break;
+ default:
+ break;
+ }
+ }
+
+ const QSGShaderEffectMaterial *oldMaterial = static_cast<const QSGShaderEffectMaterial *>(oldEffect);
+ if (oldEffect == 0 || material->cullMode() != oldMaterial->cullMode()) {
+ switch (material->cullMode()) {
+ case QSGShaderEffectMaterial::FrontFaceCulling:
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_FRONT);
+ break;
+ case QSGShaderEffectMaterial::BackFaceCulling:
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ break;
+ default:
+ glDisable(GL_CULL_FACE);
+ break;
+ }
+ }
+
+ if ((state.isMatrixDirty()) && material->m_source.respectsMatrix)
+ m_program.setUniformValue(m_matrixLoc, state.combinedMatrix());
+}
+
+char const *const *QSGCustomMaterialShader::attributeNames() const
+{
+ return m_attributeNames.constData();
+}
+
+void QSGCustomMaterialShader::initialize()
+{
+ m_opacityLoc = m_program.uniformLocation("qt_Opacity");
+ m_matrixLoc = m_program.uniformLocation("qt_ModelViewProjectionMatrix");
+}
+
+const char *QSGCustomMaterialShader::vertexShader() const
+{
+ return m_key.vertexCode.constData();
+}
+
+const char *QSGCustomMaterialShader::fragmentShader() const
+{
+ return m_key.fragmentCode.constData();
+}
+
+
+bool QSGShaderEffectMaterialKey::operator == (const QSGShaderEffectMaterialKey &other) const
+{
+ return vertexCode == other.vertexCode && fragmentCode == other.fragmentCode && className == other.className;
+}
+
+uint qHash(const QSGShaderEffectMaterialKey &key)
+{
+ return qHash(qMakePair(qMakePair(key.vertexCode, key.fragmentCode), key.className));
+}
+
+
+QHash<QSGShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > QSGShaderEffectMaterial::materialMap;
+
+QSGShaderEffectMaterial::QSGShaderEffectMaterial()
+ : m_cullMode(NoCulling)
+{
+ setFlag(Blending, true);
+}
+
+QSGMaterialType *QSGShaderEffectMaterial::type() const
+{
+ return m_type.data();
+}
+
+QSGMaterialShader *QSGShaderEffectMaterial::createShader() const
+{
+ return new QSGCustomMaterialShader(m_source, m_source.attributeNames);
+}
+
+int QSGShaderEffectMaterial::compare(const QSGMaterial *other) const
+{
+ return this - static_cast<const QSGShaderEffectMaterial *>(other);
+}
+
+void QSGShaderEffectMaterial::setCullMode(QSGShaderEffectMaterial::CullMode face)
+{
+ m_cullMode = face;
+}
+
+QSGShaderEffectMaterial::CullMode QSGShaderEffectMaterial::cullMode() const
+{
+ return m_cullMode;
+}
+
+void QSGShaderEffectMaterial::setProgramSource(const QSGShaderEffectProgram &source)
+{
+ m_source = source;
+ m_type = materialMap.value(m_source);
+ if (m_type.isNull()) {
+ m_type = QSharedPointer<QSGMaterialType>(new QSGMaterialType);
+ materialMap.insert(m_source, m_type);
+ }
+}
+
+void QSGShaderEffectMaterial::setUniforms(const QVector<QPair<QByteArray, QVariant> > &uniformValues)
+{
+ m_uniformValues = uniformValues;
+}
+
+void QSGShaderEffectMaterial::setTextureProviders(const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textures)
+{
+ m_textures = textures;
+}
+
+const QVector<QPair<QByteArray, QPointer<QSGItem> > > &QSGShaderEffectMaterial::textureProviders() const
+{
+ return m_textures;
+}
+
+void QSGShaderEffectMaterial::updateTextures() const
+{
+ for (int i = 0; i < m_textures.size(); ++i) {
+ QSGItem *item = m_textures.at(i).second;
+ if (item) {
+ QSGTextureProvider *provider = QSGTextureProvider::from(item);
+ if (provider) {
+ QSGTexture *texture = provider->texture();
+ if (!texture) {
+ qWarning("QSGShaderEffectMaterial: no texture from %s [%s]",
+ qPrintable(item->objectName()),
+ item->metaObject()->className());
+ }
+ if (QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(provider->texture())) {
+ t->updateTexture();
+ }
+ }
+ }
+ }
+}
+
+
+QSGShaderEffectNode::QSGShaderEffectNode()
+{
+ QSGNode::setFlag(UsePreprocess, true);
+}
+
+QSGShaderEffectNode::~QSGShaderEffectNode()
+{
+}
+
+void QSGShaderEffectNode::markDirtyTexture()
+{
+ markDirty(DirtyMaterial);
+}
+
+void QSGShaderEffectNode::preprocess()
+{
+ Q_ASSERT(material());
+ static_cast<QSGShaderEffectMaterial *>(material())->updateTextures();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgshadereffectnode_p.h b/src/declarative/items/qsgshadereffectnode_p.h
new file mode 100644
index 0000000000..0be4b36294
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectnode_p.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SHADEREFFECTNODE_H
+#define SHADEREFFECTNODE_H
+
+#include "qsgnode.h"
+#include "qsgmaterial.h"
+#include <private/qsgtextureprovider_p.h>
+#include <qsgitem.h>
+
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+struct QSGShaderEffectMaterialKey {
+ QByteArray vertexCode;
+ QByteArray fragmentCode;
+ const char *className;
+
+ bool operator == (const QSGShaderEffectMaterialKey &other) const;
+};
+
+uint qHash(const QSGShaderEffectMaterialKey &key);
+
+// TODO: Implement support for multisampling.
+struct QSGShaderEffectProgram : public QSGShaderEffectMaterialKey
+{
+ QSGShaderEffectProgram() : respectsOpacity(false), respectsMatrix(false) {}
+
+ QVector<QByteArray> attributeNames;
+ QSet<QByteArray> uniformNames;
+
+ uint respectsOpacity : 1;
+ uint respectsMatrix : 1;
+};
+
+
+class QSGCustomMaterialShader;
+class QSGShaderEffectMaterial : public QSGMaterial
+{
+public:
+ enum CullMode
+ {
+ NoCulling,
+ BackFaceCulling,
+ FrontFaceCulling
+ };
+
+ QSGShaderEffectMaterial();
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setCullMode(CullMode face);
+ CullMode cullMode() const;
+
+ void setProgramSource(const QSGShaderEffectProgram &);
+ void setUniforms(const QVector<QPair<QByteArray, QVariant> > &uniformValues);
+ void setTextureProviders(const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textures);
+ const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textureProviders() const;
+ void updateTextures() const;
+
+protected:
+ friend class QSGShaderEffectItem;
+ friend class QSGCustomMaterialShader;
+
+ // The type pointer needs to be unique. It is not safe to let the type object be part of the
+ // QSGShaderEffectMaterial, since it can be deleted and a new one constructed on top of the old
+ // one. The new QSGShaderEffectMaterial would then get the same type pointer as the old one, and
+ // CustomMaterialShaders based on the old one would incorrectly be used together with the new
+ // one. To guarantee that the type pointer is unique, the type object must live as long as
+ // there are any CustomMaterialShaders of that type.
+ QSharedPointer<QSGMaterialType> m_type;
+
+ QSGShaderEffectProgram m_source;
+ QVector<QPair<QByteArray, QVariant> > m_uniformValues;
+ QVector<QPair<QByteArray, QPointer<QSGItem> > > m_textures;
+ CullMode m_cullMode;
+
+ static QHash<QSGShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > materialMap;
+};
+
+
+class QSGShaderEffectMesh;
+
+class QSGShaderEffectNode : public QObject, public QSGGeometryNode
+{
+ Q_OBJECT
+public:
+ QSGShaderEffectNode();
+ virtual ~QSGShaderEffectNode();
+
+ virtual void preprocess();
+
+private Q_SLOTS:
+ void markDirtyTexture();
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SHADEREFFECTNODE_H
diff --git a/src/declarative/items/qsgshadereffectsource.cpp b/src/declarative/items/qsgshadereffectsource.cpp
new file mode 100644
index 0000000000..36d380b15f
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectsource.cpp
@@ -0,0 +1,526 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgshadereffectsource_p.h"
+
+#include "qsgitem_p.h"
+#include "qsgcanvas_p.h"
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgrenderer_p.h>
+
+#include "qglframebufferobject.h"
+#include "qmath.h"
+#include <private/qsgtexture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY)
+
+QSGShaderEffectTexture::QSGShaderEffectTexture(QSGItem *shaderSource)
+ : QSGDynamicTexture()
+ , m_item(0)
+ , m_format(GL_RGBA)
+ , m_shaderSource(shaderSource)
+ , m_renderer(0)
+ , m_fbo(0)
+ , m_multisampledFbo(0)
+#ifdef QSG_DEBUG_FBO_OVERLAY
+ , m_debugOverlay(0)
+#endif
+ , m_live(true)
+ , m_dirtyTexture(true)
+ , m_multisamplingSupportChecked(false)
+ , m_multisampling(false)
+{
+}
+
+QSGShaderEffectTexture::~QSGShaderEffectTexture()
+{
+ delete m_renderer;
+ delete m_fbo;
+ delete m_multisampledFbo;
+#ifdef QSG_DEBUG_FBO_OVERLAY
+ delete m_debugOverlay;
+#endif
+}
+
+
+int QSGShaderEffectTexture::textureId() const
+{
+ return m_fbo->texture();
+}
+
+bool QSGShaderEffectTexture::hasAlphaChannel() const
+{
+ return m_format != GL_RGB;
+}
+
+bool QSGShaderEffectTexture::hasMipmaps() const
+{
+ return m_mipmapFiltering;
+}
+
+
+void QSGShaderEffectTexture::bind()
+{
+ glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+ updateBindOptions();
+}
+
+bool QSGShaderEffectTexture::updateTexture()
+{
+ if (m_dirtyTexture) {
+ grab();
+ return true;
+ }
+ return false;
+}
+
+void QSGShaderEffectTexture::setHasMipmaps(QSGTexture::Filtering filtering)
+{
+ if (filtering == m_mipmapFiltering)
+ return;
+ m_mipmapFiltering = filtering;
+ if (filtering != None && m_fbo && !m_fbo->format().mipmap())
+ markDirtyTexture();
+}
+
+
+void QSGShaderEffectTexture::setItem(QSGNode *item)
+{
+ if (item == m_item)
+ return;
+ m_item = item;
+ markDirtyTexture();
+}
+
+void QSGShaderEffectTexture::setRect(const QRectF &rect)
+{
+ if (rect == m_rect)
+ return;
+ m_rect = rect;
+ markDirtyTexture();
+}
+
+void QSGShaderEffectTexture::setSize(const QSize &size)
+{
+ if (size == m_size)
+ return;
+ m_size = size;
+ markDirtyTexture();
+}
+
+void QSGShaderEffectTexture::setFormat(GLenum format)
+{
+ if (format == m_format)
+ return;
+ m_format = format;
+ markDirtyTexture();
+}
+
+void QSGShaderEffectTexture::setLive(bool live)
+{
+ if (live == m_live)
+ return;
+ m_live = live;
+ markDirtyTexture();
+}
+
+void QSGShaderEffectTexture::markDirtyTexture()
+{
+ if (m_live) {
+ m_dirtyTexture = true;
+ emit textureChanged();
+ }
+}
+
+void QSGShaderEffectTexture::grab()
+{
+ Q_ASSERT(m_item);
+ QSGNode *root = m_item;
+ while (root->childCount() && root->type() != QSGNode::RootNodeType)
+ root = root->childAtIndex(0);
+ if (root->type() != QSGNode::RootNodeType)
+ return;
+
+ if (m_size.isEmpty()) {
+ delete m_fbo;
+ delete m_multisampledFbo;
+ m_multisampledFbo = m_fbo = 0;
+ return;
+ }
+
+ QSGContext *context = QSGItemPrivate::get(m_shaderSource)->sceneGraphContext();
+
+ if (!m_renderer) {
+ m_renderer = context->createRenderer();
+ connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()));
+ }
+ m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
+
+ bool mipmap = m_mipmapFiltering != None;
+ if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format
+ || (!m_fbo->format().mipmap() && mipmap))
+ {
+ if (!m_multisamplingSupportChecked) {
+ QList<QByteArray> extensions = QByteArray((const char *)glGetString(GL_EXTENSIONS)).split(' ');
+ m_multisampling = extensions.contains("GL_EXT_framebuffer_multisample")
+ && extensions.contains("GL_EXT_framebuffer_blit");
+ m_multisamplingSupportChecked = true;
+ }
+ if (m_multisampling) {
+ delete m_fbo;
+ delete m_multisampledFbo;
+ QGLFramebufferObjectFormat format;
+
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setInternalTextureFormat(m_format);
+ format.setSamples(8);
+ m_multisampledFbo = new QGLFramebufferObject(m_size, format);
+
+ format.setAttachment(QGLFramebufferObject::NoAttachment);
+ format.setMipmap(m_mipmapFiltering);
+ format.setSamples(0);
+ m_fbo = new QGLFramebufferObject(m_size, format);
+
+ } else {
+ delete m_fbo;
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setInternalTextureFormat(m_format);
+ format.setMipmap(m_mipmapFiltering);
+ m_fbo = new QGLFramebufferObject(m_size, format);
+ }
+ }
+
+ // Render texture.
+ QSGNode::DirtyFlags dirty = root->dirtyFlags();
+ root->markDirty(QSGNode::DirtyNodeAdded); // Force matrix and clip update.
+ m_renderer->nodeChanged(root, QSGNode::DirtyNodeAdded); // Force render list update.
+
+#ifdef QSG_DEBUG_FBO_OVERLAY
+ if (qmlFboOverlay()) {
+ if (!m_debugOverlay)
+ m_debugOverlay = context->createRectangleNode();
+ m_debugOverlay->setRect(QRectF(0, 0, m_size.width(), m_size.height()));
+ m_debugOverlay->setColor(QColor(0xff, 0x00, 0x80, 0x40));
+ m_debugOverlay->setPenColor(QColor());
+ m_debugOverlay->setPenWidth(0);
+ m_debugOverlay->setRadius(0);
+ m_debugOverlay->update();
+ root->appendChildNode(m_debugOverlay);
+ }
+#endif
+
+ m_dirtyTexture = false;
+
+ const QGLContext *ctx = QGLContext::currentContext();
+ m_renderer->setDeviceRect(m_size);
+ m_renderer->setViewportRect(m_size);
+ m_renderer->setProjectMatrixToRect(m_rect);
+ m_renderer->setClearColor(Qt::transparent);
+
+ if (m_multisampling) {
+ m_renderer->renderScene(BindableFbo(m_multisampledFbo));
+ QRect r(0, 0, m_fbo->width(), m_fbo->height());
+ QGLFramebufferObject::blitFramebuffer(m_fbo, r, m_multisampledFbo, r);
+ } else {
+ m_renderer->renderScene(BindableFbo(m_fbo));
+ }
+
+ if (mipmap) {
+ glBindTexture(GL_TEXTURE_2D, textureId());
+ ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ }
+
+ root->markDirty(dirty | QSGNode::DirtyNodeAdded); // Force matrix, clip and render list update.
+
+#ifdef QSG_DEBUG_FBO_OVERLAY
+ if (qmlFboOverlay())
+ root->removeChildNode(m_debugOverlay);
+#endif
+}
+
+
+QSGShaderEffectSource::QSGShaderEffectSource(QSGItem *parent)
+ : QSGItem(parent)
+ , m_wrapMode(ClampToEdge)
+ , m_sourceItem(0)
+ , m_textureSize(0, 0)
+ , m_format(RGBA)
+ , m_live(true)
+ , m_hideSource(false)
+ , m_mipmap(false)
+{
+ setFlag(ItemHasContents);
+ m_texture = new QSGShaderEffectTexture(this);
+}
+
+QSGShaderEffectSource::~QSGShaderEffectSource()
+{
+ delete m_texture;
+ if (m_sourceItem)
+ QSGItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
+}
+
+QSGShaderEffectSource::WrapMode QSGShaderEffectSource::wrapMode() const
+{
+ return m_wrapMode;
+}
+
+void QSGShaderEffectSource::setWrapMode(WrapMode mode)
+{
+ if (mode == m_wrapMode)
+ return;
+ m_wrapMode = mode;
+ update();
+ emit wrapModeChanged();
+}
+
+QSGItem *QSGShaderEffectSource::sourceItem() const
+{
+ return m_sourceItem;
+}
+
+void QSGShaderEffectSource::setSourceItem(QSGItem *item)
+{
+ if (item == m_sourceItem)
+ return;
+ if (m_sourceItem)
+ QSGItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
+ m_sourceItem = item;
+ if (m_sourceItem) {
+ // TODO: Find better solution.
+ // 'm_sourceItem' needs a canvas to get a scenegraph node.
+ // The easiest way to make sure it gets a canvas is to
+ // make it a part of the same item tree as 'this'.
+ if (m_sourceItem->parentItem() == 0) {
+ m_sourceItem->setParentItem(this);
+ m_sourceItem->setVisible(false);
+ }
+ QSGItemPrivate::get(m_sourceItem)->refFromEffectItem(m_hideSource);
+ }
+ update();
+ emit sourceItemChanged();
+}
+
+QRectF QSGShaderEffectSource::sourceRect() const
+{
+ return m_sourceRect;
+}
+
+void QSGShaderEffectSource::setSourceRect(const QRectF &rect)
+{
+ if (rect == m_sourceRect)
+ return;
+ m_sourceRect = rect;
+ update();
+ emit sourceRectChanged();
+}
+
+QSize QSGShaderEffectSource::textureSize() const
+{
+ return m_textureSize;
+}
+
+void QSGShaderEffectSource::setTextureSize(const QSize &size)
+{
+ if (size == m_textureSize)
+ return;
+ m_textureSize = size;
+ update();
+ emit textureSizeChanged();
+}
+
+QSGShaderEffectSource::Format QSGShaderEffectSource::format() const
+{
+ return m_format;
+}
+
+void QSGShaderEffectSource::setFormat(QSGShaderEffectSource::Format format)
+{
+ if (format == m_format)
+ return;
+ m_format = format;
+ update();
+ emit formatChanged();
+}
+
+bool QSGShaderEffectSource::live() const
+{
+ return m_live;
+}
+
+void QSGShaderEffectSource::setLive(bool live)
+{
+ if (live == m_live)
+ return;
+ m_live = live;
+ update();
+ emit liveChanged();
+}
+
+bool QSGShaderEffectSource::hideSource() const
+{
+ return m_hideSource;
+}
+
+void QSGShaderEffectSource::setHideSource(bool hide)
+{
+ if (hide == m_hideSource)
+ return;
+ if (m_sourceItem) {
+ QSGItemPrivate::get(m_sourceItem)->refFromEffectItem(hide);
+ QSGItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
+ }
+ m_hideSource = hide;
+ update();
+ emit hideSourceChanged();
+}
+
+bool QSGShaderEffectSource::mipmap() const
+{
+ return m_mipmap;
+}
+
+void QSGShaderEffectSource::setMipmap(bool enabled)
+{
+ if (enabled == m_mipmap)
+ return;
+ printf("setting mipmap to: %d\n", enabled);
+ m_mipmap = enabled;
+ update();
+ emit mipmapChanged();
+}
+
+void QSGShaderEffectSource::grab()
+{
+ if (!m_sourceItem)
+ return;
+ QSGCanvas *canvas = m_sourceItem->canvas();
+ if (!canvas)
+ return;
+ QSGCanvasPrivate::get(canvas)->updateDirtyNodes();
+ QGLContext *glctx = const_cast<QGLContext *>(canvas->context());
+ glctx->makeCurrent();
+ qobject_cast<QSGShaderEffectTexture *>(m_texture)->grab();
+}
+
+static void get_wrap_mode(QSGShaderEffectSource::WrapMode mode, QSGTexture::WrapMode *hWrap, QSGTexture::WrapMode *vWrap)
+{
+ switch (mode) {
+ case QSGShaderEffectSource::RepeatHorizontally:
+ *hWrap = QSGTexture::Repeat;
+ *vWrap = QSGTexture::ClampToEdge;
+ break;
+ case QSGShaderEffectSource::RepeatVertically:
+ *vWrap = QSGTexture::Repeat;
+ *hWrap = QSGTexture::ClampToEdge;
+ break;
+ case QSGShaderEffectSource::Repeat:
+ *hWrap = *vWrap = QSGTexture::Repeat;
+ break;
+ default:
+ break;
+ }
+}
+
+
+QSGTexture *QSGShaderEffectSource::texture() const
+{
+ m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None);
+ m_texture->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+ QSGTexture::WrapMode h, v;
+ get_wrap_mode(m_wrapMode, &h, &v);
+ m_texture->setHorizontalWrapMode(h);
+ m_texture->setVerticalWrapMode(v);
+ return m_texture;
+}
+
+QSGNode *QSGShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ if (!m_sourceItem) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
+ if (!node) {
+ node = QSGItemPrivate::get(this)->sceneGraphContext()->createImageNode();
+ node->setFlag(QSGNode::UsePreprocess, true);
+ node->setTexture(m_texture);
+ }
+
+ QSGShaderEffectTexture *tex = qobject_cast<QSGShaderEffectTexture *>(m_texture);
+
+ tex->setItem(QSGItemPrivate::get(m_sourceItem)->itemNode());
+ QRectF sourceRect = m_sourceRect.isEmpty()
+ ? QRectF(0, 0, m_sourceItem->width(), m_sourceItem->height())
+ : m_sourceRect;
+ tex->setRect(sourceRect);
+ QSize textureSize = m_textureSize.isEmpty()
+ ? QSize(qCeil(sourceRect.width()), qCeil(sourceRect.height()))
+ : m_textureSize;
+ tex->setSize(textureSize);
+ tex->setLive(m_live);
+ tex->setFormat(GLenum(m_format));
+
+ QSGTexture::Filtering filtering = QSGItemPrivate::get(this)->smooth
+ ? QSGTexture::Linear
+ : QSGTexture::Nearest;
+ QSGTexture::Filtering mmFiltering = m_mipmap ? filtering : QSGTexture::None;
+ tex->setHasMipmaps(mmFiltering);
+ node->setMipmapFiltering(mmFiltering);
+ node->setFiltering(filtering);
+
+ QSGTexture::WrapMode hWrap, vWrap;
+ get_wrap_mode(m_wrapMode, &hWrap, &vWrap);
+
+ node->setHorizontalWrapMode(hWrap);
+ node->setVerticalWrapMode(vWrap);
+ node->setTargetRect(QRectF(0, 0, width(), height()));
+ node->setSourceRect(QRectF(0, 1, 1, -1));
+ node->update();
+
+ return node;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgshadereffectsource_p.h b/src/declarative/items/qsgshadereffectsource_p.h
new file mode 100644
index 0000000000..d8c4a18df1
--- /dev/null
+++ b/src/declarative/items/qsgshadereffectsource_p.h
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SHADEREFFECTSOURCE_H
+#define SHADEREFFECTSOURCE_H
+
+#include "qsgitem.h"
+#include <private/qsgtextureprovider_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgcontext_p.h>
+
+#include "qpointer.h"
+#include "qsize.h"
+#include "qrect.h"
+
+#define QSG_DEBUG_FBO_OVERLAY
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGNode;
+class UpdatePaintNodeData;
+class QGLFramebufferObject;
+
+class QSGShaderEffectTexture : public QSGDynamicTexture
+{
+ Q_OBJECT
+public:
+ QSGShaderEffectTexture(QSGItem *shaderSource);
+ ~QSGShaderEffectTexture();
+
+ virtual bool updateTexture();
+
+ // The item's "paint node", not effect node.
+ QSGNode *item() const { return m_item; }
+ void setItem(QSGNode *item);
+
+ QRectF rect() const { return m_rect; }
+ void setRect(const QRectF &rect);
+
+ QSize size() const { return m_size; }
+ void setSize(const QSize &size);
+
+ void setHasMipmaps(QSGTexture::Filtering filtering);
+
+ void bind();
+
+ bool hasAlphaChannel() const;
+ bool hasMipmaps() const;
+ int textureId() const;
+ QSize textureSize() const { return m_size; }
+
+ GLenum format() const { return m_format; }
+ void setFormat(GLenum format);
+
+ bool live() const { return bool(m_live); }
+ void setLive(bool live);
+
+ void grab();
+
+public Q_SLOTS:
+ void markDirtyTexture();
+
+private:
+ QSGNode *m_item;
+ QRectF m_rect;
+ QSize m_size;
+ GLenum m_format;
+
+ QSGItem *m_shaderSource;
+ QSGRenderer *m_renderer;
+ QGLFramebufferObject *m_fbo;
+ QGLFramebufferObject *m_multisampledFbo;
+
+#ifdef QSG_DEBUG_FBO_OVERLAY
+ QSGRectangleNode *m_debugOverlay;
+#endif
+
+ uint m_hWrapMode : 1;
+ uint m_vWrapMode : 1;
+ uint m_filtering : 2;
+ uint m_mipmapFiltering : 2;
+
+ uint m_live : 1;
+ uint m_dirtyTexture : 1;
+ uint m_multisamplingSupportChecked : 1;
+ uint m_multisampling : 1;
+};
+
+class QSGShaderEffectSource : public QSGItem, public QSGTextureProvider
+{
+ Q_OBJECT
+ Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
+ Q_PROPERTY(QSGItem *sourceItem READ sourceItem WRITE setSourceItem NOTIFY sourceItemChanged)
+ Q_PROPERTY(QRectF sourceRect READ sourceRect WRITE setSourceRect NOTIFY sourceRectChanged)
+ Q_PROPERTY(QSize textureSize READ textureSize WRITE setTextureSize NOTIFY textureSizeChanged)
+ Q_PROPERTY(Format format READ format WRITE setFormat NOTIFY formatChanged)
+ Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged)
+ Q_PROPERTY(bool hideSource READ hideSource WRITE setHideSource NOTIFY hideSourceChanged)
+ Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged)
+ Q_INTERFACES(QSGTextureProvider)
+ Q_ENUMS(Format WrapMode)
+public:
+ enum WrapMode {
+ ClampToEdge,
+ RepeatHorizontally,
+ RepeatVertically,
+ Repeat
+ };
+
+ enum Format {
+ Alpha = GL_ALPHA,
+ RGB = GL_RGB,
+ RGBA = GL_RGBA
+ };
+
+ QSGShaderEffectSource(QSGItem *parent = 0);
+ ~QSGShaderEffectSource();
+
+ WrapMode wrapMode() const;
+ void setWrapMode(WrapMode mode);
+
+ QSGItem *sourceItem() const;
+ void setSourceItem(QSGItem *item);
+
+ QRectF sourceRect() const;
+ void setSourceRect(const QRectF &rect);
+
+ QSize textureSize() const;
+ void setTextureSize(const QSize &size);
+
+ Format format() const;
+ void setFormat(Format format);
+
+ bool live() const;
+ void setLive(bool live);
+
+ bool hideSource() const;
+ void setHideSource(bool hide);
+
+ bool mipmap() const;
+ void setMipmap(bool enabled);
+
+ QSGTexture *texture() const;
+ const char *textureChangedSignal() const { return SIGNAL(textureChanged); }
+
+ Q_INVOKABLE void grab();
+
+Q_SIGNALS:
+ void wrapModeChanged();
+ void sourceItemChanged();
+ void sourceRectChanged();
+ void textureSizeChanged();
+ void formatChanged();
+ void liveChanged();
+ void hideSourceChanged();
+ void mipmapChanged();
+
+protected:
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private:
+ QSGTexture *m_texture;
+ WrapMode m_wrapMode;
+ QPointer<QSGItem> m_sourceItem;
+ QRectF m_sourceRect;
+ QSize m_textureSize;
+ Format m_format;
+ uint m_live : 1;
+ uint m_hideSource : 1;
+ uint m_mipmap : 1;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SHADEREFFECTSOURCE_H
diff --git a/src/declarative/items/qsgstateoperations.cpp b/src/declarative/items/qsgstateoperations.cpp
new file mode 100644
index 0000000000..5390440e39
--- /dev/null
+++ b/src/declarative/items/qsgstateoperations.cpp
@@ -0,0 +1,1347 @@
+// Commit: 726a8b16c52fe4608c89d740b47361a2b073ce01
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgstateoperations_p.h"
+#include "qsgitem_p.h"
+
+#include <private/qdeclarativestate_p_p.h>
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGParentChangePrivate : public QDeclarativeStateOperationPrivate
+{
+ Q_DECLARE_PUBLIC(QSGParentChange)
+public:
+ QSGParentChangePrivate() : target(0), parent(0), origParent(0), origStackBefore(0),
+ rewindParent(0), rewindStackBefore(0) {}
+
+ QSGItem *target;
+ QDeclarativeGuard<QSGItem> parent;
+ QDeclarativeGuard<QSGItem> origParent;
+ QDeclarativeGuard<QSGItem> origStackBefore;
+ QSGItem *rewindParent;
+ QSGItem *rewindStackBefore;
+
+ QDeclarativeNullableValue<QDeclarativeScriptString> xString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> yString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> widthString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> heightString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> scaleString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> rotationString;
+
+ void doChange(QSGItem *targetParent, QSGItem *stackBefore = 0);
+};
+
+void QSGParentChangePrivate::doChange(QSGItem *targetParent, QSGItem *stackBefore)
+{
+ if (targetParent && target && target->parentItem()) {
+ Q_Q(QSGParentChange);
+ bool ok;
+ const QTransform &transform = target->parentItem()->itemTransform(targetParent, &ok);
+ if (transform.type() >= QTransform::TxShear || !ok) {
+ qmlInfo(q) << QSGParentChange::tr("Unable to preserve appearance under complex transform");
+ ok = false;
+ }
+
+ qreal scale = 1;
+ qreal rotation = 0;
+ bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
+ if (ok && !isRotate) {
+ if (transform.m11() == transform.m22())
+ scale = transform.m11();
+ else {
+ qmlInfo(q) << QSGParentChange::tr("Unable to preserve appearance under non-uniform scale");
+ ok = false;
+ }
+ } else if (ok && isRotate) {
+ if (transform.m11() == transform.m22())
+ scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
+ else {
+ qmlInfo(q) << QSGParentChange::tr("Unable to preserve appearance under non-uniform scale");
+ ok = false;
+ }
+
+ if (scale != 0)
+ rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI;
+ else {
+ qmlInfo(q) << QSGParentChange::tr("Unable to preserve appearance under scale of 0");
+ ok = false;
+ }
+ }
+
+ const QPointF &point = transform.map(QPointF(target->x(),target->y()));
+ qreal x = point.x();
+ qreal y = point.y();
+
+ // setParentItem will update the transformOriginPoint if needed
+ target->setParentItem(targetParent);
+
+ if (ok && target->transformOrigin() != QSGItem::TopLeft) {
+ qreal tempxt = target->transformOriginPoint().x();
+ qreal tempyt = target->transformOriginPoint().y();
+ QTransform t;
+ t.translate(-tempxt, -tempyt);
+ t.rotate(rotation);
+ t.scale(scale, scale);
+ t.translate(tempxt, tempyt);
+ const QPointF &offset = t.map(QPointF(0,0));
+ x += offset.x();
+ y += offset.y();
+ }
+
+ if (ok) {
+ //qDebug() << x << y << rotation << scale;
+ target->setX(x);
+ target->setY(y);
+ target->setRotation(target->rotation() + rotation);
+ target->setScale(target->scale() * scale);
+ }
+ } else if (target) {
+ target->setParentItem(targetParent);
+ }
+
+ //restore the original stack position.
+ //### if stackBefore has also been reparented this won't work
+ if (stackBefore)
+ target->stackBefore(stackBefore);
+}
+
+QSGParentChange::QSGParentChange(QObject *parent)
+ : QDeclarativeStateOperation(*(new QSGParentChangePrivate), parent)
+{
+}
+
+QSGParentChange::~QSGParentChange()
+{
+}
+
+QDeclarativeScriptString QSGParentChange::x() const
+{
+ Q_D(const QSGParentChange);
+ return d->xString.value;
+}
+
+void QSGParentChange::setX(QDeclarativeScriptString x)
+{
+ Q_D(QSGParentChange);
+ d->xString = x;
+}
+
+bool QSGParentChange::xIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->xString.isValid();
+}
+
+QDeclarativeScriptString QSGParentChange::y() const
+{
+ Q_D(const QSGParentChange);
+ return d->yString.value;
+}
+
+void QSGParentChange::setY(QDeclarativeScriptString y)
+{
+ Q_D(QSGParentChange);
+ d->yString = y;
+}
+
+bool QSGParentChange::yIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->yString.isValid();
+}
+
+QDeclarativeScriptString QSGParentChange::width() const
+{
+ Q_D(const QSGParentChange);
+ return d->widthString.value;
+}
+
+void QSGParentChange::setWidth(QDeclarativeScriptString width)
+{
+ Q_D(QSGParentChange);
+ d->widthString = width;
+}
+
+bool QSGParentChange::widthIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->widthString.isValid();
+}
+
+QDeclarativeScriptString QSGParentChange::height() const
+{
+ Q_D(const QSGParentChange);
+ return d->heightString.value;
+}
+
+void QSGParentChange::setHeight(QDeclarativeScriptString height)
+{
+ Q_D(QSGParentChange);
+ d->heightString = height;
+}
+
+bool QSGParentChange::heightIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->heightString.isValid();
+}
+
+QDeclarativeScriptString QSGParentChange::scale() const
+{
+ Q_D(const QSGParentChange);
+ return d->scaleString.value;
+}
+
+void QSGParentChange::setScale(QDeclarativeScriptString scale)
+{
+ Q_D(QSGParentChange);
+ d->scaleString = scale;
+}
+
+bool QSGParentChange::scaleIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->scaleString.isValid();
+}
+
+QDeclarativeScriptString QSGParentChange::rotation() const
+{
+ Q_D(const QSGParentChange);
+ return d->rotationString.value;
+}
+
+void QSGParentChange::setRotation(QDeclarativeScriptString rotation)
+{
+ Q_D(QSGParentChange);
+ d->rotationString = rotation;
+}
+
+bool QSGParentChange::rotationIsSet() const
+{
+ Q_D(const QSGParentChange);
+ return d->rotationString.isValid();
+}
+
+QSGItem *QSGParentChange::originalParent() const
+{
+ Q_D(const QSGParentChange);
+ return d->origParent;
+}
+
+QSGItem *QSGParentChange::object() const
+{
+ Q_D(const QSGParentChange);
+ return d->target;
+}
+
+void QSGParentChange::setObject(QSGItem *target)
+{
+ Q_D(QSGParentChange);
+ d->target = target;
+}
+
+QSGItem *QSGParentChange::parent() const
+{
+ Q_D(const QSGParentChange);
+ return d->parent;
+}
+
+void QSGParentChange::setParent(QSGItem *parent)
+{
+ Q_D(QSGParentChange);
+ d->parent = parent;
+}
+
+QDeclarativeStateOperation::ActionList QSGParentChange::actions()
+{
+ Q_D(QSGParentChange);
+ if (!d->target || !d->parent)
+ return ActionList();
+
+ ActionList actions;
+
+ QDeclarativeAction a;
+ a.event = this;
+ actions << a;
+
+ if (d->xString.isValid()) {
+ bool ok = false;
+ QString script = d->xString.value.script();
+ qreal x = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction xa(d->target, QLatin1String("x"), x);
+ actions << xa;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("x")));
+ QDeclarativeAction xa;
+ xa.property = newBinding->property();
+ xa.toBinding = newBinding;
+ xa.fromValue = xa.property.read();
+ xa.deletableToBinding = true;
+ actions << xa;
+ }
+ }
+
+ if (d->yString.isValid()) {
+ bool ok = false;
+ QString script = d->yString.value.script();
+ qreal y = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction ya(d->target, QLatin1String("y"), y);
+ actions << ya;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("y")));
+ QDeclarativeAction ya;
+ ya.property = newBinding->property();
+ ya.toBinding = newBinding;
+ ya.fromValue = ya.property.read();
+ ya.deletableToBinding = true;
+ actions << ya;
+ }
+ }
+
+ if (d->scaleString.isValid()) {
+ bool ok = false;
+ QString script = d->scaleString.value.script();
+ qreal scale = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction sa(d->target, QLatin1String("scale"), scale);
+ actions << sa;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("scale")));
+ QDeclarativeAction sa;
+ sa.property = newBinding->property();
+ sa.toBinding = newBinding;
+ sa.fromValue = sa.property.read();
+ sa.deletableToBinding = true;
+ actions << sa;
+ }
+ }
+
+ if (d->rotationString.isValid()) {
+ bool ok = false;
+ QString script = d->rotationString.value.script();
+ qreal rotation = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction ra(d->target, QLatin1String("rotation"), rotation);
+ actions << ra;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("rotation")));
+ QDeclarativeAction ra;
+ ra.property = newBinding->property();
+ ra.toBinding = newBinding;
+ ra.fromValue = ra.property.read();
+ ra.deletableToBinding = true;
+ actions << ra;
+ }
+ }
+
+ if (d->widthString.isValid()) {
+ bool ok = false;
+ QString script = d->widthString.value.script();
+ qreal width = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction wa(d->target, QLatin1String("width"), width);
+ actions << wa;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("width")));
+ QDeclarativeAction wa;
+ wa.property = newBinding->property();
+ wa.toBinding = newBinding;
+ wa.fromValue = wa.property.read();
+ wa.deletableToBinding = true;
+ actions << wa;
+ }
+ }
+
+ if (d->heightString.isValid()) {
+ bool ok = false;
+ QString script = d->heightString.value.script();
+ qreal height = script.toFloat(&ok);
+ if (ok) {
+ QDeclarativeAction ha(d->target, QLatin1String("height"), height);
+ actions << ha;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this));
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("height")));
+ QDeclarativeAction ha;
+ ha.property = newBinding->property();
+ ha.toBinding = newBinding;
+ ha.fromValue = ha.property.read();
+ ha.deletableToBinding = true;
+ actions << ha;
+ }
+ }
+
+ return actions;
+}
+
+void QSGParentChange::saveOriginals()
+{
+ Q_D(QSGParentChange);
+ saveCurrentValues();
+ d->origParent = d->rewindParent;
+ d->origStackBefore = d->rewindStackBefore;
+}
+
+/*void QSGParentChange::copyOriginals(QDeclarativeActionEvent *other)
+{
+ Q_D(QSGParentChange);
+ QSGParentChange *pc = static_cast<QSGParentChange*>(other);
+
+ d->origParent = pc->d_func()->rewindParent;
+ d->origStackBefore = pc->d_func()->rewindStackBefore;
+
+ saveCurrentValues();
+}*/
+
+void QSGParentChange::execute(Reason)
+{
+ Q_D(QSGParentChange);
+ d->doChange(d->parent);
+}
+
+bool QSGParentChange::isReversable()
+{
+ return true;
+}
+
+void QSGParentChange::reverse(Reason)
+{
+ Q_D(QSGParentChange);
+ d->doChange(d->origParent, d->origStackBefore);
+}
+
+QString QSGParentChange::typeName() const
+{
+ return QLatin1String("ParentChange");
+}
+
+bool QSGParentChange::override(QDeclarativeActionEvent*other)
+{
+ Q_D(QSGParentChange);
+ if (other->typeName() != QLatin1String("ParentChange"))
+ return false;
+ if (QSGParentChange *otherPC = static_cast<QSGParentChange*>(other))
+ return (d->target == otherPC->object());
+ return false;
+}
+
+void QSGParentChange::saveCurrentValues()
+{
+ Q_D(QSGParentChange);
+ if (!d->target) {
+ d->rewindParent = 0;
+ d->rewindStackBefore = 0;
+ return;
+ }
+
+ d->rewindParent = d->target->parentItem();
+ d->rewindStackBefore = 0;
+
+ if (!d->rewindParent)
+ return;
+
+ QList<QSGItem *> children = d->rewindParent->childItems();
+ for (int ii = 0; ii < children.count() - 1; ++ii) {
+ if (children.at(ii) == d->target) {
+ d->rewindStackBefore = children.at(ii + 1);
+ break;
+ }
+ }
+}
+
+void QSGParentChange::rewind()
+{
+ Q_D(QSGParentChange);
+ d->doChange(d->rewindParent, d->rewindStackBefore);
+}
+
+class QSGAnchorSetPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGAnchorSet)
+public:
+ QSGAnchorSetPrivate()
+ : usedAnchors(0), resetAnchors(0), fill(0),
+ centerIn(0)/*, leftMargin(0), rightMargin(0), topMargin(0), bottomMargin(0),
+ margins(0), vCenterOffset(0), hCenterOffset(0), baselineOffset(0)*/
+ {
+ }
+
+ QSGAnchors::Anchors usedAnchors;
+ QSGAnchors::Anchors resetAnchors;
+
+ QSGItem *fill;
+ QSGItem *centerIn;
+
+ QDeclarativeScriptString leftScript;
+ QDeclarativeScriptString rightScript;
+ QDeclarativeScriptString topScript;
+ QDeclarativeScriptString bottomScript;
+ QDeclarativeScriptString hCenterScript;
+ QDeclarativeScriptString vCenterScript;
+ QDeclarativeScriptString baselineScript;
+
+ /*qreal leftMargin;
+ qreal rightMargin;
+ qreal topMargin;
+ qreal bottomMargin;
+ qreal margins;
+ qreal vCenterOffset;
+ qreal hCenterOffset;
+ qreal baselineOffset;*/
+};
+
+QSGAnchorSet::QSGAnchorSet(QObject *parent)
+ : QObject(*new QSGAnchorSetPrivate, parent)
+{
+}
+
+QSGAnchorSet::~QSGAnchorSet()
+{
+}
+
+QDeclarativeScriptString QSGAnchorSet::top() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->topScript;
+}
+
+void QSGAnchorSet::setTop(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::TopAnchor;
+ d->topScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetTop();
+}
+
+void QSGAnchorSet::resetTop()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::TopAnchor;
+ d->topScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::TopAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::bottom() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->bottomScript;
+}
+
+void QSGAnchorSet::setBottom(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::BottomAnchor;
+ d->bottomScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetBottom();
+}
+
+void QSGAnchorSet::resetBottom()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::BottomAnchor;
+ d->bottomScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::BottomAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::verticalCenter() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->vCenterScript;
+}
+
+void QSGAnchorSet::setVerticalCenter(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::VCenterAnchor;
+ d->vCenterScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetVerticalCenter();
+}
+
+void QSGAnchorSet::resetVerticalCenter()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::VCenterAnchor;
+ d->vCenterScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::VCenterAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::baseline() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->baselineScript;
+}
+
+void QSGAnchorSet::setBaseline(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::BaselineAnchor;
+ d->baselineScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetBaseline();
+}
+
+void QSGAnchorSet::resetBaseline()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::BaselineAnchor;
+ d->baselineScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::BaselineAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::left() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->leftScript;
+}
+
+void QSGAnchorSet::setLeft(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::LeftAnchor;
+ d->leftScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetLeft();
+}
+
+void QSGAnchorSet::resetLeft()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::LeftAnchor;
+ d->leftScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::LeftAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::right() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->rightScript;
+}
+
+void QSGAnchorSet::setRight(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::RightAnchor;
+ d->rightScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetRight();
+}
+
+void QSGAnchorSet::resetRight()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::RightAnchor;
+ d->rightScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::RightAnchor;
+}
+
+QDeclarativeScriptString QSGAnchorSet::horizontalCenter() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->hCenterScript;
+}
+
+void QSGAnchorSet::setHorizontalCenter(const QDeclarativeScriptString &edge)
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors |= QSGAnchors::HCenterAnchor;
+ d->hCenterScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetHorizontalCenter();
+}
+
+void QSGAnchorSet::resetHorizontalCenter()
+{
+ Q_D(QSGAnchorSet);
+ d->usedAnchors &= ~QSGAnchors::HCenterAnchor;
+ d->hCenterScript = QDeclarativeScriptString();
+ d->resetAnchors |= QSGAnchors::HCenterAnchor;
+}
+
+QSGItem *QSGAnchorSet::fill() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->fill;
+}
+
+void QSGAnchorSet::setFill(QSGItem *f)
+{
+ Q_D(QSGAnchorSet);
+ d->fill = f;
+}
+
+void QSGAnchorSet::resetFill()
+{
+ setFill(0);
+}
+
+QSGItem *QSGAnchorSet::centerIn() const
+{
+ Q_D(const QSGAnchorSet);
+ return d->centerIn;
+}
+
+void QSGAnchorSet::setCenterIn(QSGItem* c)
+{
+ Q_D(QSGAnchorSet);
+ d->centerIn = c;
+}
+
+void QSGAnchorSet::resetCenterIn()
+{
+ setCenterIn(0);
+}
+
+
+class QSGAnchorChangesPrivate : public QDeclarativeStateOperationPrivate
+{
+public:
+ QSGAnchorChangesPrivate()
+ : target(0), anchorSet(new QSGAnchorSet),
+ leftBinding(0), rightBinding(0), hCenterBinding(0),
+ topBinding(0), bottomBinding(0), vCenterBinding(0), baselineBinding(0),
+ origLeftBinding(0), origRightBinding(0), origHCenterBinding(0),
+ origTopBinding(0), origBottomBinding(0), origVCenterBinding(0),
+ origBaselineBinding(0)
+ {
+
+ }
+ ~QSGAnchorChangesPrivate() { delete anchorSet; }
+
+ QSGItem *target;
+ QSGAnchorSet *anchorSet;
+
+ QDeclarativeBinding *leftBinding;
+ QDeclarativeBinding *rightBinding;
+ QDeclarativeBinding *hCenterBinding;
+ QDeclarativeBinding *topBinding;
+ QDeclarativeBinding *bottomBinding;
+ QDeclarativeBinding *vCenterBinding;
+ QDeclarativeBinding *baselineBinding;
+
+ QDeclarativeAbstractBinding *origLeftBinding;
+ QDeclarativeAbstractBinding *origRightBinding;
+ QDeclarativeAbstractBinding *origHCenterBinding;
+ QDeclarativeAbstractBinding *origTopBinding;
+ QDeclarativeAbstractBinding *origBottomBinding;
+ QDeclarativeAbstractBinding *origVCenterBinding;
+ QDeclarativeAbstractBinding *origBaselineBinding;
+
+ QSGAnchorLine rewindLeft;
+ QSGAnchorLine rewindRight;
+ QSGAnchorLine rewindHCenter;
+ QSGAnchorLine rewindTop;
+ QSGAnchorLine rewindBottom;
+ QSGAnchorLine rewindVCenter;
+ QSGAnchorLine rewindBaseline;
+
+ qreal fromX;
+ qreal fromY;
+ qreal fromWidth;
+ qreal fromHeight;
+
+ qreal toX;
+ qreal toY;
+ qreal toWidth;
+ qreal toHeight;
+
+ qreal rewindX;
+ qreal rewindY;
+ qreal rewindWidth;
+ qreal rewindHeight;
+
+ bool applyOrigLeft;
+ bool applyOrigRight;
+ bool applyOrigHCenter;
+ bool applyOrigTop;
+ bool applyOrigBottom;
+ bool applyOrigVCenter;
+ bool applyOrigBaseline;
+
+ QDeclarativeNullableValue<qreal> origWidth;
+ QDeclarativeNullableValue<qreal> origHeight;
+ qreal origX;
+ qreal origY;
+
+ QList<QDeclarativeAbstractBinding*> oldBindings;
+
+ QDeclarativeProperty leftProp;
+ QDeclarativeProperty rightProp;
+ QDeclarativeProperty hCenterProp;
+ QDeclarativeProperty topProp;
+ QDeclarativeProperty bottomProp;
+ QDeclarativeProperty vCenterProp;
+ QDeclarativeProperty baselineProp;
+};
+
+QSGAnchorChanges::QSGAnchorChanges(QObject *parent)
+ : QDeclarativeStateOperation(*(new QSGAnchorChangesPrivate), parent)
+{
+}
+
+QSGAnchorChanges::~QSGAnchorChanges()
+{
+}
+
+QSGAnchorChanges::ActionList QSGAnchorChanges::actions()
+{
+ Q_D(QSGAnchorChanges);
+ d->leftBinding = d->rightBinding = d->hCenterBinding = d->topBinding
+ = d->bottomBinding = d->vCenterBinding = d->baselineBinding = 0;
+
+ d->leftProp = QDeclarativeProperty(d->target, QLatin1String("anchors.left"));
+ d->rightProp = QDeclarativeProperty(d->target, QLatin1String("anchors.right"));
+ d->hCenterProp = QDeclarativeProperty(d->target, QLatin1String("anchors.horizontalCenter"));
+ d->topProp = QDeclarativeProperty(d->target, QLatin1String("anchors.top"));
+ d->bottomProp = QDeclarativeProperty(d->target, QLatin1String("anchors.bottom"));
+ d->vCenterProp = QDeclarativeProperty(d->target, QLatin1String("anchors.verticalCenter"));
+ d->baselineProp = QDeclarativeProperty(d->target, QLatin1String("anchors.baseline"));
+
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::LeftAnchor) {
+ d->leftBinding = new QDeclarativeBinding(d->anchorSet->d_func()->leftScript.script(), d->target, qmlContext(this));
+ d->leftBinding->setTarget(d->leftProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::RightAnchor) {
+ d->rightBinding = new QDeclarativeBinding(d->anchorSet->d_func()->rightScript.script(), d->target, qmlContext(this));
+ d->rightBinding->setTarget(d->rightProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::HCenterAnchor) {
+ d->hCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->hCenterScript.script(), d->target, qmlContext(this));
+ d->hCenterBinding->setTarget(d->hCenterProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::TopAnchor) {
+ d->topBinding = new QDeclarativeBinding(d->anchorSet->d_func()->topScript.script(), d->target, qmlContext(this));
+ d->topBinding->setTarget(d->topProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::BottomAnchor) {
+ d->bottomBinding = new QDeclarativeBinding(d->anchorSet->d_func()->bottomScript.script(), d->target, qmlContext(this));
+ d->bottomBinding->setTarget(d->bottomProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::VCenterAnchor) {
+ d->vCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->vCenterScript.script(), d->target, qmlContext(this));
+ d->vCenterBinding->setTarget(d->vCenterProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QSGAnchors::BaselineAnchor) {
+ d->baselineBinding = new QDeclarativeBinding(d->anchorSet->d_func()->baselineScript.script(), d->target, qmlContext(this));
+ d->baselineBinding->setTarget(d->baselineProp);
+ }
+
+ QDeclarativeAction a;
+ a.event = this;
+ return ActionList() << a;
+}
+
+QSGAnchorSet *QSGAnchorChanges::anchors()
+{
+ Q_D(QSGAnchorChanges);
+ return d->anchorSet;
+}
+
+QSGItem *QSGAnchorChanges::object() const
+{
+ Q_D(const QSGAnchorChanges);
+ return d->target;
+}
+
+void QSGAnchorChanges::setObject(QSGItem *target)
+{
+ Q_D(QSGAnchorChanges);
+ d->target = target;
+}
+
+void QSGAnchorChanges::execute(Reason reason)
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+ //incorporate any needed "reverts"
+ if (d->applyOrigLeft) {
+ if (!d->origLeftBinding)
+ targetPrivate->anchors()->resetLeft();
+ QDeclarativePropertyPrivate::setBinding(d->leftProp, d->origLeftBinding);
+ }
+ if (d->applyOrigRight) {
+ if (!d->origRightBinding)
+ targetPrivate->anchors()->resetRight();
+ QDeclarativePropertyPrivate::setBinding(d->rightProp, d->origRightBinding);
+ }
+ if (d->applyOrigHCenter) {
+ if (!d->origHCenterBinding)
+ targetPrivate->anchors()->resetHorizontalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding);
+ }
+ if (d->applyOrigTop) {
+ if (!d->origTopBinding)
+ targetPrivate->anchors()->resetTop();
+ QDeclarativePropertyPrivate::setBinding(d->topProp, d->origTopBinding);
+ }
+ if (d->applyOrigBottom) {
+ if (!d->origBottomBinding)
+ targetPrivate->anchors()->resetBottom();
+ QDeclarativePropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding);
+ }
+ if (d->applyOrigVCenter) {
+ if (!d->origVCenterBinding)
+ targetPrivate->anchors()->resetVerticalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding);
+ }
+ if (d->applyOrigBaseline) {
+ if (!d->origBaselineBinding)
+ targetPrivate->anchors()->resetBaseline();
+ QDeclarativePropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding);
+ }
+
+ //destroy old bindings
+ if (reason == ActualChange) {
+ for (int i = 0; i < d->oldBindings.size(); ++i) {
+ QDeclarativeAbstractBinding *binding = d->oldBindings.at(i);
+ if (binding)
+ binding->destroy();
+ }
+ d->oldBindings.clear();
+ }
+
+ //reset any anchors that have been specified as "undefined"
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::LeftAnchor) {
+ targetPrivate->anchors()->resetLeft();
+ QDeclarativePropertyPrivate::setBinding(d->leftProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::RightAnchor) {
+ targetPrivate->anchors()->resetRight();
+ QDeclarativePropertyPrivate::setBinding(d->rightProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::HCenterAnchor) {
+ targetPrivate->anchors()->resetHorizontalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->hCenterProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::TopAnchor) {
+ targetPrivate->anchors()->resetTop();
+ QDeclarativePropertyPrivate::setBinding(d->topProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::BottomAnchor) {
+ targetPrivate->anchors()->resetBottom();
+ QDeclarativePropertyPrivate::setBinding(d->bottomProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::VCenterAnchor) {
+ targetPrivate->anchors()->resetVerticalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->vCenterProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QSGAnchors::BaselineAnchor) {
+ targetPrivate->anchors()->resetBaseline();
+ QDeclarativePropertyPrivate::setBinding(d->baselineProp, 0);
+ }
+
+ //set any anchors that have been specified
+ if (d->leftBinding)
+ QDeclarativePropertyPrivate::setBinding(d->leftBinding->property(), d->leftBinding);
+ if (d->rightBinding)
+ QDeclarativePropertyPrivate::setBinding(d->rightBinding->property(), d->rightBinding);
+ if (d->hCenterBinding)
+ QDeclarativePropertyPrivate::setBinding(d->hCenterBinding->property(), d->hCenterBinding);
+ if (d->topBinding)
+ QDeclarativePropertyPrivate::setBinding(d->topBinding->property(), d->topBinding);
+ if (d->bottomBinding)
+ QDeclarativePropertyPrivate::setBinding(d->bottomBinding->property(), d->bottomBinding);
+ if (d->vCenterBinding)
+ QDeclarativePropertyPrivate::setBinding(d->vCenterBinding->property(), d->vCenterBinding);
+ if (d->baselineBinding)
+ QDeclarativePropertyPrivate::setBinding(d->baselineBinding->property(), d->baselineBinding);
+}
+
+bool QSGAnchorChanges::isReversable()
+{
+ return true;
+}
+
+void QSGAnchorChanges::reverse(Reason reason)
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+ //reset any anchors set by the state
+ if (d->leftBinding) {
+ targetPrivate->anchors()->resetLeft();
+ QDeclarativePropertyPrivate::setBinding(d->leftBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->leftBinding->destroy(); d->leftBinding = 0;
+ }
+ }
+ if (d->rightBinding) {
+ targetPrivate->anchors()->resetRight();
+ QDeclarativePropertyPrivate::setBinding(d->rightBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->rightBinding->destroy(); d->rightBinding = 0;
+ }
+ }
+ if (d->hCenterBinding) {
+ targetPrivate->anchors()->resetHorizontalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->hCenterBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->hCenterBinding->destroy(); d->hCenterBinding = 0;
+ }
+ }
+ if (d->topBinding) {
+ targetPrivate->anchors()->resetTop();
+ QDeclarativePropertyPrivate::setBinding(d->topBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->topBinding->destroy(); d->topBinding = 0;
+ }
+ }
+ if (d->bottomBinding) {
+ targetPrivate->anchors()->resetBottom();
+ QDeclarativePropertyPrivate::setBinding(d->bottomBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->bottomBinding->destroy(); d->bottomBinding = 0;
+ }
+ }
+ if (d->vCenterBinding) {
+ targetPrivate->anchors()->resetVerticalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->vCenterBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->vCenterBinding->destroy(); d->vCenterBinding = 0;
+ }
+ }
+ if (d->baselineBinding) {
+ targetPrivate->anchors()->resetBaseline();
+ QDeclarativePropertyPrivate::setBinding(d->baselineBinding->property(), 0);
+ if (reason == ActualChange) {
+ d->baselineBinding->destroy(); d->baselineBinding = 0;
+ }
+ }
+
+ //restore previous anchors
+ if (d->origLeftBinding)
+ QDeclarativePropertyPrivate::setBinding(d->leftProp, d->origLeftBinding);
+ if (d->origRightBinding)
+ QDeclarativePropertyPrivate::setBinding(d->rightProp, d->origRightBinding);
+ if (d->origHCenterBinding)
+ QDeclarativePropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding);
+ if (d->origTopBinding)
+ QDeclarativePropertyPrivate::setBinding(d->topProp, d->origTopBinding);
+ if (d->origBottomBinding)
+ QDeclarativePropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding);
+ if (d->origVCenterBinding)
+ QDeclarativePropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding);
+ if (d->origBaselineBinding)
+ QDeclarativePropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding);
+
+ //restore any absolute geometry changed by the state's anchors
+ QSGAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QSGAnchors::Vertical_Mask;
+ QSGAnchors::Anchors origVAnchors = targetPrivate->anchors()->usedAnchors() & QSGAnchors::Vertical_Mask;
+ QSGAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QSGAnchors::Horizontal_Mask;
+ QSGAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QSGAnchors::Horizontal_Mask;
+
+ bool stateSetWidth = (stateHAnchors &&
+ stateHAnchors != QSGAnchors::LeftAnchor &&
+ stateHAnchors != QSGAnchors::RightAnchor &&
+ stateHAnchors != QSGAnchors::HCenterAnchor);
+ bool origSetWidth = (origHAnchors &&
+ origHAnchors != QSGAnchors::LeftAnchor &&
+ origHAnchors != QSGAnchors::RightAnchor &&
+ origHAnchors != QSGAnchors::HCenterAnchor);
+ if (d->origWidth.isValid() && stateSetWidth && !origSetWidth)
+ d->target->setWidth(d->origWidth.value);
+
+ bool stateSetHeight = (stateVAnchors &&
+ stateVAnchors != QSGAnchors::TopAnchor &&
+ stateVAnchors != QSGAnchors::BottomAnchor &&
+ stateVAnchors != QSGAnchors::VCenterAnchor &&
+ stateVAnchors != QSGAnchors::BaselineAnchor);
+ bool origSetHeight = (origVAnchors &&
+ origVAnchors != QSGAnchors::TopAnchor &&
+ origVAnchors != QSGAnchors::BottomAnchor &&
+ origVAnchors != QSGAnchors::VCenterAnchor &&
+ origVAnchors != QSGAnchors::BaselineAnchor);
+ if (d->origHeight.isValid() && stateSetHeight && !origSetHeight)
+ d->target->setHeight(d->origHeight.value);
+
+ if (stateHAnchors && !origHAnchors)
+ d->target->setX(d->origX);
+
+ if (stateVAnchors && !origVAnchors)
+ d->target->setY(d->origY);
+}
+
+QString QSGAnchorChanges::typeName() const
+{
+ return QLatin1String("AnchorChanges");
+}
+
+QList<QDeclarativeAction> QSGAnchorChanges::additionalActions()
+{
+ Q_D(QSGAnchorChanges);
+ QList<QDeclarativeAction> extra;
+
+ QSGAnchors::Anchors combined = d->anchorSet->d_func()->usedAnchors | d->anchorSet->d_func()->resetAnchors;
+ bool hChange = combined & QSGAnchors::Horizontal_Mask;
+ bool vChange = combined & QSGAnchors::Vertical_Mask;
+
+ if (d->target) {
+ QDeclarativeAction a;
+ if (hChange && d->fromX != d->toX) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("x"));
+ a.toValue = d->toX;
+ extra << a;
+ }
+ if (vChange && d->fromY != d->toY) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("y"));
+ a.toValue = d->toY;
+ extra << a;
+ }
+ if (hChange && d->fromWidth != d->toWidth) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("width"));
+ a.toValue = d->toWidth;
+ extra << a;
+ }
+ if (vChange && d->fromHeight != d->toHeight) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("height"));
+ a.toValue = d->toHeight;
+ extra << a;
+ }
+ }
+
+ return extra;
+}
+
+bool QSGAnchorChanges::changesBindings()
+{
+ return true;
+}
+
+void QSGAnchorChanges::saveOriginals()
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ d->origLeftBinding = QDeclarativePropertyPrivate::binding(d->leftProp);
+ d->origRightBinding = QDeclarativePropertyPrivate::binding(d->rightProp);
+ d->origHCenterBinding = QDeclarativePropertyPrivate::binding(d->hCenterProp);
+ d->origTopBinding = QDeclarativePropertyPrivate::binding(d->topProp);
+ d->origBottomBinding = QDeclarativePropertyPrivate::binding(d->bottomProp);
+ d->origVCenterBinding = QDeclarativePropertyPrivate::binding(d->vCenterProp);
+ d->origBaselineBinding = QDeclarativePropertyPrivate::binding(d->baselineProp);
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+ if (targetPrivate->widthValid)
+ d->origWidth = d->target->width();
+ if (targetPrivate->heightValid)
+ d->origHeight = d->target->height();
+ d->origX = d->target->x();
+ d->origY = d->target->y();
+
+ d->applyOrigLeft = d->applyOrigRight = d->applyOrigHCenter = d->applyOrigTop
+ = d->applyOrigBottom = d->applyOrigVCenter = d->applyOrigBaseline = false;
+
+ saveCurrentValues();
+}
+
+void QSGAnchorChanges::copyOriginals(QDeclarativeActionEvent *other)
+{
+ Q_D(QSGAnchorChanges);
+ QSGAnchorChanges *ac = static_cast<QSGAnchorChanges*>(other);
+ QSGAnchorChangesPrivate *acp = ac->d_func();
+
+ QSGAnchors::Anchors combined = acp->anchorSet->d_func()->usedAnchors |
+ acp->anchorSet->d_func()->resetAnchors;
+
+ //probably also need to revert some things
+ d->applyOrigLeft = (combined & QSGAnchors::LeftAnchor);
+ d->applyOrigRight = (combined & QSGAnchors::RightAnchor);
+ d->applyOrigHCenter = (combined & QSGAnchors::HCenterAnchor);
+ d->applyOrigTop = (combined & QSGAnchors::TopAnchor);
+ d->applyOrigBottom = (combined & QSGAnchors::BottomAnchor);
+ d->applyOrigVCenter = (combined & QSGAnchors::VCenterAnchor);
+ d->applyOrigBaseline = (combined & QSGAnchors::BaselineAnchor);
+
+ d->origLeftBinding = acp->origLeftBinding;
+ d->origRightBinding = acp->origRightBinding;
+ d->origHCenterBinding = acp->origHCenterBinding;
+ d->origTopBinding = acp->origTopBinding;
+ d->origBottomBinding = acp->origBottomBinding;
+ d->origVCenterBinding = acp->origVCenterBinding;
+ d->origBaselineBinding = acp->origBaselineBinding;
+
+ d->origWidth = acp->origWidth;
+ d->origHeight = acp->origHeight;
+ d->origX = acp->origX;
+ d->origY = acp->origY;
+
+ d->oldBindings.clear();
+ d->oldBindings << acp->leftBinding << acp->rightBinding << acp->hCenterBinding
+ << acp->topBinding << acp->bottomBinding << acp->baselineBinding;
+
+ saveCurrentValues();
+}
+
+void QSGAnchorChanges::clearBindings()
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ //### should this (saving "from" values) be moved to saveCurrentValues()?
+ d->fromX = d->target->x();
+ d->fromY = d->target->y();
+ d->fromWidth = d->target->width();
+ d->fromHeight = d->target->height();
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+ //reset any anchors with corresponding reverts
+ //reset any anchors that have been specified as "undefined"
+ //reset any anchors that we'll be setting in the state
+ QSGAnchors::Anchors combined = d->anchorSet->d_func()->resetAnchors |
+ d->anchorSet->d_func()->usedAnchors;
+ if (d->applyOrigLeft || (combined & QSGAnchors::LeftAnchor)) {
+ targetPrivate->anchors()->resetLeft();
+ QDeclarativePropertyPrivate::setBinding(d->leftProp, 0);
+ }
+ if (d->applyOrigRight || (combined & QSGAnchors::RightAnchor)) {
+ targetPrivate->anchors()->resetRight();
+ QDeclarativePropertyPrivate::setBinding(d->rightProp, 0);
+ }
+ if (d->applyOrigHCenter || (combined & QSGAnchors::HCenterAnchor)) {
+ targetPrivate->anchors()->resetHorizontalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->hCenterProp, 0);
+ }
+ if (d->applyOrigTop || (combined & QSGAnchors::TopAnchor)) {
+ targetPrivate->anchors()->resetTop();
+ QDeclarativePropertyPrivate::setBinding(d->topProp, 0);
+ }
+ if (d->applyOrigBottom || (combined & QSGAnchors::BottomAnchor)) {
+ targetPrivate->anchors()->resetBottom();
+ QDeclarativePropertyPrivate::setBinding(d->bottomProp, 0);
+ }
+ if (d->applyOrigVCenter || (combined & QSGAnchors::VCenterAnchor)) {
+ targetPrivate->anchors()->resetVerticalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->vCenterProp, 0);
+ }
+ if (d->applyOrigBaseline || (combined & QSGAnchors::BaselineAnchor)) {
+ targetPrivate->anchors()->resetBaseline();
+ QDeclarativePropertyPrivate::setBinding(d->baselineProp, 0);
+ }
+}
+
+bool QSGAnchorChanges::override(QDeclarativeActionEvent*other)
+{
+ if (other->typeName() != QLatin1String("AnchorChanges"))
+ return false;
+ if (static_cast<QDeclarativeActionEvent*>(this) == other)
+ return true;
+ if (static_cast<QSGAnchorChanges*>(other)->object() == object())
+ return true;
+ return false;
+}
+
+void QSGAnchorChanges::rewind()
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+
+ //restore previous values (but not previous bindings, i.e. anchors)
+ d->target->setX(d->rewindX);
+ d->target->setY(d->rewindY);
+ if (targetPrivate->widthValid) {
+ d->target->setWidth(d->rewindWidth);
+ }
+ if (targetPrivate->heightValid) {
+ d->target->setHeight(d->rewindHeight);
+ }
+}
+
+void QSGAnchorChanges::saveCurrentValues()
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ QSGItemPrivate *targetPrivate = QSGItemPrivate::get(d->target);
+ d->rewindLeft = targetPrivate->anchors()->left();
+ d->rewindRight = targetPrivate->anchors()->right();
+ d->rewindHCenter = targetPrivate->anchors()->horizontalCenter();
+ d->rewindTop = targetPrivate->anchors()->top();
+ d->rewindBottom = targetPrivate->anchors()->bottom();
+ d->rewindVCenter = targetPrivate->anchors()->verticalCenter();
+ d->rewindBaseline = targetPrivate->anchors()->baseline();
+
+ d->rewindX = d->target->x();
+ d->rewindY = d->target->y();
+ d->rewindWidth = d->target->width();
+ d->rewindHeight = d->target->height();
+}
+
+void QSGAnchorChanges::saveTargetValues()
+{
+ Q_D(QSGAnchorChanges);
+ if (!d->target)
+ return;
+
+ d->toX = d->target->x();
+ d->toY = d->target->y();
+ d->toWidth = d->target->width();
+ d->toHeight = d->target->height();
+}
+
+#include <moc_qsgstateoperations_p.cpp>
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/items/qsgstateoperations_p.h b/src/declarative/items/qsgstateoperations_p.h
new file mode 100644
index 0000000000..f816e36b82
--- /dev/null
+++ b/src/declarative/items/qsgstateoperations_p.h
@@ -0,0 +1,275 @@
+// Commit: 84c47bbb133304d7ef35642fa1fbb17619d4a43d
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSTATEOPERATIONS_H
+#define QSGSTATEOPERATIONS_H
+
+#include "qsgitem.h"
+#include "qsganchors_p.h"
+
+#include <private/qdeclarativestate_p.h>
+
+#include <QtDeclarative/qdeclarativescriptstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGParentChangePrivate;
+class Q_AUTOTEST_EXPORT QSGParentChange : public QDeclarativeStateOperation, public QDeclarativeActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGParentChange)
+
+ Q_PROPERTY(QSGItem *target READ object WRITE setObject)
+ Q_PROPERTY(QSGItem *parent READ parent WRITE setParent)
+ Q_PROPERTY(QDeclarativeScriptString x READ x WRITE setX)
+ Q_PROPERTY(QDeclarativeScriptString y READ y WRITE setY)
+ Q_PROPERTY(QDeclarativeScriptString width READ width WRITE setWidth)
+ Q_PROPERTY(QDeclarativeScriptString height READ height WRITE setHeight)
+ Q_PROPERTY(QDeclarativeScriptString scale READ scale WRITE setScale)
+ Q_PROPERTY(QDeclarativeScriptString rotation READ rotation WRITE setRotation)
+public:
+ QSGParentChange(QObject *parent=0);
+ ~QSGParentChange();
+
+ QSGItem *object() const;
+ void setObject(QSGItem *);
+
+ QSGItem *parent() const;
+ void setParent(QSGItem *);
+
+ QSGItem *originalParent() const;
+
+ QDeclarativeScriptString x() const;
+ void setX(QDeclarativeScriptString x);
+ bool xIsSet() const;
+
+ QDeclarativeScriptString y() const;
+ void setY(QDeclarativeScriptString y);
+ bool yIsSet() const;
+
+ QDeclarativeScriptString width() const;
+ void setWidth(QDeclarativeScriptString width);
+ bool widthIsSet() const;
+
+ QDeclarativeScriptString height() const;
+ void setHeight(QDeclarativeScriptString height);
+ bool heightIsSet() const;
+
+ QDeclarativeScriptString scale() const;
+ void setScale(QDeclarativeScriptString scale);
+ bool scaleIsSet() const;
+
+ QDeclarativeScriptString rotation() const;
+ void setRotation(QDeclarativeScriptString rotation);
+ bool rotationIsSet() const;
+
+ virtual ActionList actions();
+
+ virtual void saveOriginals();
+ //virtual void copyOriginals(QDeclarativeActionEvent*);
+ virtual void execute(Reason reason = ActualChange);
+ virtual bool isReversable();
+ virtual void reverse(Reason reason = ActualChange);
+ virtual QString typeName() const;
+ virtual bool override(QDeclarativeActionEvent*other);
+ virtual void rewind();
+ virtual void saveCurrentValues();
+};
+
+class QSGAnchorChanges;
+class QSGAnchorSetPrivate;
+class Q_AUTOTEST_EXPORT QSGAnchorSet : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativeScriptString left READ left WRITE setLeft RESET resetLeft)
+ Q_PROPERTY(QDeclarativeScriptString right READ right WRITE setRight RESET resetRight)
+ Q_PROPERTY(QDeclarativeScriptString horizontalCenter READ horizontalCenter WRITE setHorizontalCenter RESET resetHorizontalCenter)
+ Q_PROPERTY(QDeclarativeScriptString top READ top WRITE setTop RESET resetTop)
+ Q_PROPERTY(QDeclarativeScriptString bottom READ bottom WRITE setBottom RESET resetBottom)
+ Q_PROPERTY(QDeclarativeScriptString verticalCenter READ verticalCenter WRITE setVerticalCenter RESET resetVerticalCenter)
+ Q_PROPERTY(QDeclarativeScriptString baseline READ baseline WRITE setBaseline RESET resetBaseline)
+ //Q_PROPERTY(QSGItem *fill READ fill WRITE setFill RESET resetFill)
+ //Q_PROPERTY(QSGItem *centerIn READ centerIn WRITE setCenterIn RESET resetCenterIn)
+
+ /*Q_PROPERTY(qreal margins READ margins WRITE setMargins NOTIFY marginsChanged)
+ Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
+ Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
+ Q_PROPERTY(qreal horizontalCenterOffset READ horizontalCenterOffset WRITE setHorizontalCenterOffset NOTIFY horizontalCenterOffsetChanged())
+ Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
+ Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
+ Q_PROPERTY(qreal verticalCenterOffset READ verticalCenterOffset WRITE setVerticalCenterOffset NOTIFY verticalCenterOffsetChanged())
+ Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged())*/
+
+public:
+ QSGAnchorSet(QObject *parent=0);
+ virtual ~QSGAnchorSet();
+
+ QDeclarativeScriptString left() const;
+ void setLeft(const QDeclarativeScriptString &edge);
+ void resetLeft();
+
+ QDeclarativeScriptString right() const;
+ void setRight(const QDeclarativeScriptString &edge);
+ void resetRight();
+
+ QDeclarativeScriptString horizontalCenter() const;
+ void setHorizontalCenter(const QDeclarativeScriptString &edge);
+ void resetHorizontalCenter();
+
+ QDeclarativeScriptString top() const;
+ void setTop(const QDeclarativeScriptString &edge);
+ void resetTop();
+
+ QDeclarativeScriptString bottom() const;
+ void setBottom(const QDeclarativeScriptString &edge);
+ void resetBottom();
+
+ QDeclarativeScriptString verticalCenter() const;
+ void setVerticalCenter(const QDeclarativeScriptString &edge);
+ void resetVerticalCenter();
+
+ QDeclarativeScriptString baseline() const;
+ void setBaseline(const QDeclarativeScriptString &edge);
+ void resetBaseline();
+
+ QSGItem *fill() const;
+ void setFill(QSGItem *);
+ void resetFill();
+
+ QSGItem *centerIn() const;
+ void setCenterIn(QSGItem *);
+ void resetCenterIn();
+
+ /*qreal leftMargin() const;
+ void setLeftMargin(qreal);
+
+ qreal rightMargin() const;
+ void setRightMargin(qreal);
+
+ qreal horizontalCenterOffset() const;
+ void setHorizontalCenterOffset(qreal);
+
+ qreal topMargin() const;
+ void setTopMargin(qreal);
+
+ qreal bottomMargin() const;
+ void setBottomMargin(qreal);
+
+ qreal margins() const;
+ void setMargins(qreal);
+
+ qreal verticalCenterOffset() const;
+ void setVerticalCenterOffset(qreal);
+
+ qreal baselineOffset() const;
+ void setBaselineOffset(qreal);*/
+
+ QSGAnchors::Anchors usedAnchors() const;
+
+/*Q_SIGNALS:
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void marginsChanged();
+ void verticalCenterOffsetChanged();
+ void horizontalCenterOffsetChanged();
+ void baselineOffsetChanged();*/
+
+private:
+ friend class QSGAnchorChanges;
+ Q_DISABLE_COPY(QSGAnchorSet)
+ Q_DECLARE_PRIVATE(QSGAnchorSet)
+};
+
+class QSGAnchorChangesPrivate;
+class Q_AUTOTEST_EXPORT QSGAnchorChanges : public QDeclarativeStateOperation, public QDeclarativeActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGAnchorChanges)
+
+ Q_PROPERTY(QSGItem *target READ object WRITE setObject)
+ Q_PROPERTY(QSGAnchorSet *anchors READ anchors CONSTANT)
+
+public:
+ QSGAnchorChanges(QObject *parent=0);
+ ~QSGAnchorChanges();
+
+ virtual ActionList actions();
+
+ QSGAnchorSet *anchors();
+
+ QSGItem *object() const;
+ void setObject(QSGItem *);
+
+ virtual void execute(Reason reason = ActualChange);
+ virtual bool isReversable();
+ virtual void reverse(Reason reason = ActualChange);
+ virtual QString typeName() const;
+ virtual bool override(QDeclarativeActionEvent*other);
+ virtual bool changesBindings();
+ virtual void saveOriginals();
+ virtual bool needsCopy() { return true; }
+ virtual void copyOriginals(QDeclarativeActionEvent*);
+ virtual void clearBindings();
+ virtual void rewind();
+ virtual void saveCurrentValues();
+
+ QList<QDeclarativeAction> additionalActions();
+ virtual void saveTargetValues();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGParentChange)
+QML_DECLARE_TYPE(QSGAnchorSet)
+QML_DECLARE_TYPE(QSGAnchorChanges)
+
+QT_END_HEADER
+
+#endif // QSGSTATEOPERATIONS_H
+
diff --git a/src/declarative/items/qsgtext.cpp b/src/declarative/items/qsgtext.cpp
new file mode 100644
index 0000000000..ab4669eb45
--- /dev/null
+++ b/src/declarative/items/qsgtext.cpp
@@ -0,0 +1,1240 @@
+// Commit: a5c3c11e3e2204da6c8be9af98b38929366fafb8
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtext_p.h"
+#include "qsgtext_p_p.h"
+
+#include <private/qsgdistancefieldglyphcache_p.h>
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include "qsgtextnode_p.h"
+#include "qsgimage_p_p.h"
+#include <private/qsgtexture_p.h>
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qabstracttextdocumentlayout.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qtextdocument.h>
+#include <QtGui/qtextobject.h>
+#include <QtGui/qtextcursor.h>
+#include <QtGui/qapplication.h>
+
+#include <private/qdeclarativestyledtext_p.h>
+#include <private/qdeclarativepixmapcache_p.h>
+
+#include <qmath.h>
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
+
+class QSGTextDocumentWithImageResources : public QTextDocument {
+ Q_OBJECT
+
+public:
+ QSGTextDocumentWithImageResources(QSGText *parent);
+ virtual ~QSGTextDocumentWithImageResources();
+
+ void setText(const QString &);
+ int resourcesLoading() const { return outstanding; }
+
+protected:
+ QVariant loadResource(int type, const QUrl &name);
+
+private slots:
+ void requestFinished();
+
+private:
+ QHash<QUrl, QDeclarativePixmap *> m_resources;
+
+ int outstanding;
+ static QSet<QUrl> errors;
+};
+
+DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE);
+
+QString QSGTextPrivate::elideChar = QString(0x2026);
+
+QSGTextPrivate::QSGTextPrivate()
+: color((QRgb)0), style(QSGText::Normal), hAlign(QSGText::AlignLeft),
+ vAlign(QSGText::AlignTop), elideMode(QSGText::ElideNone),
+ format(QSGText::AutoText), wrapMode(QSGText::NoWrap), lineHeight(1),
+ lineHeightMode(QSGText::ProportionalHeight), lineCount(1), maximumLineCount(INT_MAX),
+ maximumLineCountValid(false),
+ texture(0),
+ imageCacheDirty(true), updateOnComponentComplete(true),
+ richText(false), singleline(false), cacheAllTextAsImage(true), internalWidthUpdate(false),
+ requireImplicitWidth(false), truncated(false), hAlignImplicit(true), rightToLeftText(false),
+ naturalWidth(0), doc(0), nodeType(NodeIsNull)
+{
+ cacheAllTextAsImage = enableImageCache();
+}
+
+void QSGTextPrivate::init()
+{
+ Q_Q(QSGText);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QSGItem::ItemHasContents);
+}
+
+QSGTextDocumentWithImageResources::QSGTextDocumentWithImageResources(QSGText *parent)
+: QTextDocument(parent), outstanding(0)
+{
+ setUndoRedoEnabled(false);
+}
+
+QSGTextDocumentWithImageResources::~QSGTextDocumentWithImageResources()
+{
+ if (!m_resources.isEmpty())
+ qDeleteAll(m_resources);
+}
+
+QVariant QSGTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
+{
+ QDeclarativeContext *context = qmlContext(parent());
+ QUrl url = context->resolvedUrl(name);
+
+ if (type == QTextDocument::ImageResource) {
+ QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url);
+
+ if (iter == m_resources.end()) {
+ QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url);
+ iter = m_resources.insert(name, p);
+
+ if (p->isLoading()) {
+ p->connectFinished(this, SLOT(requestFinished()));
+ outstanding++;
+ }
+ }
+
+ QDeclarativePixmap *p = *iter;
+ if (p->isReady()) {
+ return p->pixmap();
+ } else if (p->isError()) {
+ if (!errors.contains(url)) {
+ errors.insert(url);
+ qmlInfo(parent()) << p->error();
+ }
+ }
+ }
+
+ return QTextDocument::loadResource(type,url); // The *resolved* URL
+}
+
+void QSGTextDocumentWithImageResources::requestFinished()
+{
+ outstanding--;
+ if (outstanding == 0) {
+ QSGText *textItem = static_cast<QSGText*>(parent());
+ QString text = textItem->text();
+#ifndef QT_NO_TEXTHTMLPARSER
+ setHtml(text);
+#else
+ setPlainText(text);
+#endif
+ QSGTextPrivate *d = QSGTextPrivate::get(textItem);
+ d->updateLayout();
+ }
+}
+
+void QSGTextDocumentWithImageResources::setText(const QString &text)
+{
+ if (!m_resources.isEmpty()) {
+ qDeleteAll(m_resources);
+ m_resources.clear();
+ outstanding = 0;
+ }
+
+#ifndef QT_NO_TEXTHTMLPARSER
+ setHtml(text);
+#else
+ setPlainText(text);
+#endif
+}
+
+QSet<QUrl> QSGTextDocumentWithImageResources::errors;
+
+QSGTextPrivate::~QSGTextPrivate()
+{
+}
+
+qreal QSGTextPrivate::getImplicitWidth() const
+{
+ if (!requireImplicitWidth) {
+ // We don't calculate implicitWidth unless it is required.
+ // We need to force a size update now to ensure implicitWidth is calculated
+ QSGTextPrivate *me = const_cast<QSGTextPrivate*>(this);
+ me->requireImplicitWidth = true;
+ me->updateSize();
+ }
+ return implicitWidth;
+}
+
+void QSGTextPrivate::updateLayout()
+{
+ Q_Q(QSGText);
+ if (!q->isComponentComplete()) {
+ updateOnComponentComplete = true;
+ return;
+ }
+
+ // Setup instance of QTextLayout for all cases other than richtext
+ if (!richText) {
+ layout.clearLayout();
+ layout.setFont(font);
+ if (format != QSGText::StyledText) {
+ QString tmp = text;
+ tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ singleline = !tmp.contains(QChar::LineSeparator);
+ if (singleline && !maximumLineCountValid && elideMode != QSGText::ElideNone && q->widthValid()) {
+ QFontMetrics fm(font);
+ tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width()); // XXX still worth layout...?
+ if (tmp != text && !truncated) {
+ truncated = true;
+ emit q->truncatedChanged();
+ }
+ }
+ layout.setText(tmp);
+ } else {
+ singleline = false;
+ QDeclarativeStyledText::parse(text, layout);
+ }
+ } else {
+ ensureDoc();
+ QTextBlockFormat::LineHeightTypes type;
+ type = lineHeightMode == QSGText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight;
+ QTextBlockFormat blockFormat;
+ blockFormat.setLineHeight((lineHeightMode == QSGText::FixedHeight ? lineHeight : lineHeight * 100), type);
+ for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next()) {
+ QTextCursor cursor(it);
+ cursor.setBlockFormat(blockFormat);
+ }
+ }
+
+ updateSize();
+}
+
+void QSGTextPrivate::updateSize()
+{
+ Q_Q(QSGText);
+
+ if (!q->isComponentComplete()) {
+ updateOnComponentComplete = true;
+ return;
+ }
+
+ if (!requireImplicitWidth) {
+ emit q->implicitWidthChanged();
+ // if the implicitWidth is used, then updateSize() has already been called (recursively)
+ if (requireImplicitWidth)
+ return;
+ }
+
+ invalidateImageCache();
+
+ QFontMetrics fm(font);
+ if (text.isEmpty()) {
+ q->setImplicitWidth(0);
+ q->setImplicitHeight(fm.height());
+ paintedSize = QSize(0, fm.height());
+ emit q->paintedSizeChanged();
+ q->update();
+ return;
+ }
+
+ int dy = q->height();
+ QSize size(0, 0);
+
+ //setup instance of QTextLayout for all cases other than richtext
+ if (!richText) {
+ QRect textRect = setupTextLayout();
+ layedOutTextRect = textRect;
+ size = textRect.size();
+ dy -= size.height();
+ } else {
+ singleline = false; // richtext can't elide or be optimized for single-line case
+ ensureDoc();
+ doc->setDefaultFont(font);
+ QSGText::HAlignment horizontalAlignment = q->effectiveHAlign();
+ if (rightToLeftText) {
+ if (horizontalAlignment == QSGText::AlignLeft)
+ horizontalAlignment = QSGText::AlignRight;
+ else if (horizontalAlignment == QSGText::AlignRight)
+ horizontalAlignment = QSGText::AlignLeft;
+ }
+ QTextOption option;
+ option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
+ option.setWrapMode(QTextOption::WrapMode(wrapMode));
+ doc->setDefaultTextOption(option);
+ if (requireImplicitWidth && q->widthValid()) {
+ doc->setTextWidth(-1);
+ naturalWidth = doc->idealWidth();
+ }
+ if (wrapMode != QSGText::NoWrap && q->widthValid())
+ doc->setTextWidth(q->width());
+ else
+ doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
+ dy -= (int)doc->size().height();
+ QSize dsize = doc->size().toSize();
+ layedOutTextRect = QRect(QPoint(0,0), dsize);
+ size = QSize(int(doc->idealWidth()),dsize.height());
+ }
+ int yoff = 0;
+
+ if (q->heightValid()) {
+ if (vAlign == QSGText::AlignBottom)
+ yoff = dy;
+ else if (vAlign == QSGText::AlignVCenter)
+ yoff = dy/2;
+ }
+ q->setBaselineOffset(fm.ascent() + yoff);
+
+ //### need to comfirm cost of always setting these for richText
+ internalWidthUpdate = true;
+ if (!q->widthValid())
+ q->setImplicitWidth(size.width());
+ else if (requireImplicitWidth)
+ q->setImplicitWidth(naturalWidth);
+ internalWidthUpdate = false;
+
+ q->setImplicitHeight(size.height());
+ if (paintedSize != size) {
+ paintedSize = size;
+ emit q->paintedSizeChanged();
+ }
+ q->update();
+}
+
+/*!
+ Lays out the QSGTextPrivate::layout QTextLayout in the constraints of the QSGText.
+
+ Returns the size of the final text. This can be used to position the text vertically (the text is
+ already absolutely positioned horizontally).
+*/
+QRect QSGTextPrivate::setupTextLayout()
+{
+ // ### text layout handling should be profiled and optimized as needed
+ // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
+ Q_Q(QSGText);
+ layout.setCacheEnabled(true);
+
+ qreal lineWidth = 0;
+ int visibleCount = 0;
+
+ //set manual width
+ if (q->widthValid())
+ lineWidth = q->width();
+
+ QTextOption textOption = layout.textOption();
+ textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
+ textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
+ layout.setTextOption(textOption);
+
+ bool elideText = false;
+ bool truncate = false;
+
+ QFontMetrics fm(layout.font());
+ elidePos = QPointF();
+
+ if (requireImplicitWidth && q->widthValid()) {
+ // requires an extra layout
+ layout.beginLayout();
+ forever {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+ }
+ layout.endLayout();
+ QRectF br;
+ for (int i = 0; i < layout.lineCount(); ++i) {
+ QTextLine line = layout.lineAt(i);
+ br = br.united(line.naturalTextRect());
+ }
+ naturalWidth = br.width();
+ }
+
+ if (maximumLineCountValid) {
+ layout.beginLayout();
+ if (!lineWidth)
+ lineWidth = INT_MAX;
+ int linesLeft = maximumLineCount;
+ int visibleTextLength = 0;
+ while (linesLeft > 0) {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+
+ visibleCount++;
+ if (lineWidth)
+ line.setLineWidth(lineWidth);
+ visibleTextLength += line.textLength();
+
+ if (--linesLeft == 0) {
+ if (visibleTextLength < text.length()) {
+ truncate = true;
+ if (elideMode==QSGText::ElideRight && q->widthValid()) {
+ qreal elideWidth = fm.width(elideChar);
+ // Need to correct for alignment
+ line.setLineWidth(lineWidth-elideWidth);
+ if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
+ line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
+ elidePos.setX(line.naturalTextRect().left() - elideWidth);
+ } else {
+ elidePos.setX(line.naturalTextRect().right());
+ }
+ elideText = true;
+ }
+ }
+ }
+ }
+ layout.endLayout();
+
+ //Update truncated
+ if (truncated != truncate) {
+ truncated = truncate;
+ emit q->truncatedChanged();
+ }
+ } else {
+ layout.beginLayout();
+ forever {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+ visibleCount++;
+ if (lineWidth)
+ line.setLineWidth(lineWidth);
+ }
+ layout.endLayout();
+ }
+
+ qreal height = 0;
+ QRectF br;
+ for (int i = 0; i < layout.lineCount(); ++i) {
+ QTextLine line = layout.lineAt(i);
+ // set line spacing
+ line.setPosition(QPointF(line.position().x(), height));
+ if (elideText && i == layout.lineCount()-1) {
+ elidePos.setY(height + fm.ascent());
+ br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent())));
+ }
+ br = br.united(line.naturalTextRect());
+ height += (lineHeightMode == QSGText::FixedHeight) ? lineHeight : line.height() * lineHeight;
+ }
+ br.setHeight(height);
+
+ if (!q->widthValid())
+ naturalWidth = br.width();
+
+ //Update the number of visible lines
+ if (lineCount != visibleCount) {
+ lineCount = visibleCount;
+ emit q->lineCountChanged();
+ }
+
+ return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
+}
+
+/*!
+ Returns a painted version of the QSGTextPrivate::layout QTextLayout.
+ If \a drawStyle is true, the style color overrides all colors in the document.
+*/
+QPixmap QSGTextPrivate::textLayoutImage(bool drawStyle)
+{
+ QSize size = layedOutTextRect.size();
+
+ //paint text
+ QPixmap img(size);
+ if (!size.isEmpty()) {
+ img.fill(Qt::transparent);
+#ifdef Q_WS_MAC
+ bool oldSmooth = qt_applefontsmoothing_enabled;
+ qt_applefontsmoothing_enabled = false;
+#endif
+ QPainter p(&img);
+#ifdef Q_WS_MAC
+ qt_applefontsmoothing_enabled = oldSmooth;
+#endif
+ drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
+ }
+ return img;
+}
+
+/*!
+ Paints the QSGTextPrivate::layout QTextLayout into \a painter at \a pos. If
+ \a drawStyle is true, the style color overrides all colors in the document.
+*/
+void QSGTextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle)
+{
+ if (drawStyle)
+ painter->setPen(styleColor);
+ else
+ painter->setPen(color);
+ painter->setFont(font);
+ layout.draw(painter, pos);
+ if (!elidePos.isNull())
+ painter->drawText(pos + elidePos, elideChar);
+}
+
+/*!
+ Returns a painted version of the QSGTextPrivate::doc QTextDocument.
+ If \a drawStyle is true, the style color overrides all colors in the document.
+*/
+QPixmap QSGTextPrivate::textDocumentImage(bool drawStyle)
+{
+ QSize size = doc->size().toSize();
+
+ //paint text
+ QPixmap img(size);
+ img.fill(Qt::transparent);
+#ifdef Q_WS_MAC
+ bool oldSmooth = qt_applefontsmoothing_enabled;
+ qt_applefontsmoothing_enabled = false;
+#endif
+ QPainter p(&img);
+#ifdef Q_WS_MAC
+ qt_applefontsmoothing_enabled = oldSmooth;
+#endif
+
+ QAbstractTextDocumentLayout::PaintContext context;
+
+ QTextOption oldOption(doc->defaultTextOption());
+ if (drawStyle) {
+ context.palette.setColor(QPalette::Text, styleColor);
+ QTextOption colorOption(doc->defaultTextOption());
+ colorOption.setFlags(QTextOption::SuppressColors);
+ doc->setDefaultTextOption(colorOption);
+ } else {
+ context.palette.setColor(QPalette::Text, color);
+ }
+ doc->documentLayout()->draw(&p, context);
+ if (drawStyle)
+ doc->setDefaultTextOption(oldOption);
+ return img;
+}
+
+/*!
+ Mark the image cache as dirty.
+*/
+void QSGTextPrivate::invalidateImageCache()
+{
+ Q_Q(QSGText);
+
+ if(cacheAllTextAsImage || (!QSGDistanceFieldGlyphCache::distanceFieldEnabled() && style != QSGText::Normal)){//If actually using the image cache
+ if (imageCacheDirty)
+ return;
+
+ imageCacheDirty = true;
+ imageCache = QPixmap();
+ }
+ if (q->isComponentComplete())
+ q->update();
+}
+
+/*!
+ Tests if the image cache is dirty, and repaints it if it is.
+*/
+void QSGTextPrivate::checkImageCache()
+{
+ if (!imageCacheDirty)
+ return;
+
+ if (text.isEmpty()) {
+
+ imageCache = QPixmap();
+
+ } else {
+
+ QPixmap textImage;
+ QPixmap styledImage;
+
+ if (richText) {
+ textImage = textDocumentImage(false);
+ if (style != QSGText::Normal)
+ styledImage = textDocumentImage(true); //### should use styleColor
+ } else {
+ textImage = textLayoutImage(false);
+ if (style != QSGText::Normal)
+ styledImage = textLayoutImage(true); //### should use styleColor
+ }
+
+ switch (style) {
+ case QSGText::Outline:
+ imageCache = drawOutline(textImage, styledImage);
+ break;
+ case QSGText::Sunken:
+ imageCache = drawOutline(textImage, styledImage, -1);
+ break;
+ case QSGText::Raised:
+ imageCache = drawOutline(textImage, styledImage, 1);
+ break;
+ default:
+ imageCache = textImage;
+ break;
+ }
+
+ }
+
+ imageCacheDirty = false;
+}
+
+/*!
+ Ensures the QSGTextPrivate::doc variable is set to a valid text document
+*/
+void QSGTextPrivate::ensureDoc()
+{
+ if (!doc) {
+ Q_Q(QSGText);
+ doc = new QSGTextDocumentWithImageResources(q);
+ doc->setDocumentMargin(0);
+ }
+}
+
+/*!
+ Draw \a styleSource as an outline around \a source and return the new image.
+*/
+QPixmap QSGTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource)
+{
+ QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
+ img.fill(Qt::transparent);
+
+ QPainter ppm(&img);
+
+ QPoint pos(0, 0);
+ pos += QPoint(-1, 0);
+ ppm.drawPixmap(pos, styleSource);
+ pos += QPoint(2, 0);
+ ppm.drawPixmap(pos, styleSource);
+ pos += QPoint(-1, -1);
+ ppm.drawPixmap(pos, styleSource);
+ pos += QPoint(0, 2);
+ ppm.drawPixmap(pos, styleSource);
+
+ pos += QPoint(0, -1);
+ ppm.drawPixmap(pos, source);
+ ppm.end();
+
+ return img;
+}
+
+/*!
+ Draw \a styleSource below \a source at \a yOffset and return the new image.
+*/
+QPixmap QSGTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset)
+{
+ QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
+ img.fill(Qt::transparent);
+
+ QPainter ppm(&img);
+
+ ppm.drawPixmap(QPoint(0, yOffset), styleSource);
+ ppm.drawPixmap(0, 0, source);
+
+ ppm.end();
+
+ return img;
+}
+
+QSGText::QSGText(QSGItem *parent)
+: QSGImplicitSizeItem(*(new QSGTextPrivate), parent)
+{
+ Q_D(QSGText);
+ d->init();
+}
+
+QSGText::~QSGText()
+{
+}
+
+QFont QSGText::font() const
+{
+ Q_D(const QSGText);
+ return d->sourceFont;
+}
+
+void QSGText::setFont(const QFont &font)
+{
+ Q_D(QSGText);
+ if (d->sourceFont == font)
+ return;
+
+ d->sourceFont = font;
+ QFont oldFont = d->font;
+ d->font = font;
+ if (QSGDistanceFieldGlyphCache::distanceFieldEnabled())
+ d->font.setHintingPreference(QFont::PreferNoHinting);
+
+ if (d->font.pointSizeF() != -1) {
+ // 0.5pt resolution
+ qreal size = qRound(d->font.pointSizeF()*2.0);
+ d->font.setPointSizeF(size/2.0);
+ }
+
+ if (oldFont != d->font)
+ d->updateLayout();
+
+ emit fontChanged(d->sourceFont);
+}
+
+QString QSGText::text() const
+{
+ Q_D(const QSGText);
+ return d->text;
+}
+
+void QSGText::setText(const QString &n)
+{
+ Q_D(QSGText);
+ if (d->text == n)
+ return;
+
+ d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n));
+ d->text = n;
+ if (isComponentComplete()) {
+ if (d->richText) {
+ d->ensureDoc();
+ d->doc->setText(n);
+ d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+ } else {
+ d->rightToLeftText = d->text.isRightToLeft();
+ }
+ d->determineHorizontalAlignment();
+ }
+ d->updateLayout();
+ emit textChanged(d->text);
+}
+
+QColor QSGText::color() const
+{
+ Q_D(const QSGText);
+ return d->color;
+}
+
+void QSGText::setColor(const QColor &color)
+{
+ Q_D(QSGText);
+ if (d->color == color)
+ return;
+
+ d->color = color;
+ d->invalidateImageCache();
+ emit colorChanged(d->color);
+}
+
+QSGText::TextStyle QSGText::style() const
+{
+ Q_D(const QSGText);
+ return d->style;
+}
+
+void QSGText::setStyle(QSGText::TextStyle style)
+{
+ Q_D(QSGText);
+ if (d->style == style)
+ return;
+
+ // changing to/from Normal requires the boundingRect() to change
+ if (isComponentComplete() && (d->style == Normal || style == Normal))
+ update();
+ d->style = style;
+ d->invalidateImageCache();
+ emit styleChanged(d->style);
+}
+
+QColor QSGText::styleColor() const
+{
+ Q_D(const QSGText);
+ return d->styleColor;
+}
+
+void QSGText::setStyleColor(const QColor &color)
+{
+ Q_D(QSGText);
+ if (d->styleColor == color)
+ return;
+
+ d->styleColor = color;
+ d->invalidateImageCache();
+ emit styleColorChanged(d->styleColor);
+}
+
+QSGText::HAlignment QSGText::hAlign() const
+{
+ Q_D(const QSGText);
+ return d->hAlign;
+}
+
+void QSGText::setHAlign(HAlignment align)
+{
+ Q_D(QSGText);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete())
+ d->updateLayout();
+}
+
+void QSGText::resetHAlign()
+{
+ Q_D(QSGText);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete())
+ d->updateLayout();
+}
+
+QSGText::HAlignment QSGText::effectiveHAlign() const
+{
+ Q_D(const QSGText);
+ QSGText::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QSGText::AlignLeft:
+ effectiveAlignment = QSGText::AlignRight;
+ break;
+ case QSGText::AlignRight:
+ effectiveAlignment = QSGText::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QSGTextPrivate::setHAlign(QSGText::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QSGText);
+ if (hAlign != alignment || forceAlign) {
+ QSGText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+
+ emit q->horizontalAlignmentChanged(hAlign);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QSGTextPrivate::determineHorizontalAlignment()
+{
+ Q_Q(QSGText);
+ if (hAlignImplicit && q->isComponentComplete()) {
+ bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
+ return setHAlign(alignToRight ? QSGText::AlignRight : QSGText::AlignLeft);
+ }
+ return false;
+}
+
+void QSGTextPrivate::mirrorChange()
+{
+ Q_Q(QSGText);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QSGText::AlignRight || hAlign == QSGText::AlignLeft)) {
+ updateLayout();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+QTextDocument *QSGTextPrivate::textDocument()
+{
+ return doc;
+}
+
+QSGText::VAlignment QSGText::vAlign() const
+{
+ Q_D(const QSGText);
+ return d->vAlign;
+}
+
+void QSGText::setVAlign(VAlignment align)
+{
+ Q_D(QSGText);
+ if (d->vAlign == align)
+ return;
+
+ d->vAlign = align;
+ emit verticalAlignmentChanged(align);
+}
+
+QSGText::WrapMode QSGText::wrapMode() const
+{
+ Q_D(const QSGText);
+ return d->wrapMode;
+}
+
+void QSGText::setWrapMode(WrapMode mode)
+{
+ Q_D(QSGText);
+ if (mode == d->wrapMode)
+ return;
+
+ d->wrapMode = mode;
+ d->updateLayout();
+
+ emit wrapModeChanged();
+}
+
+int QSGText::lineCount() const
+{
+ Q_D(const QSGText);
+ return d->lineCount;
+}
+
+bool QSGText::truncated() const
+{
+ Q_D(const QSGText);
+ return d->truncated;
+}
+
+int QSGText::maximumLineCount() const
+{
+ Q_D(const QSGText);
+ return d->maximumLineCount;
+}
+
+void QSGText::setMaximumLineCount(int lines)
+{
+ Q_D(QSGText);
+
+ d->maximumLineCountValid = lines==INT_MAX ? false : true;
+ if (d->maximumLineCount != lines) {
+ d->maximumLineCount = lines;
+ d->updateLayout();
+ emit maximumLineCountChanged();
+ }
+}
+
+void QSGText::resetMaximumLineCount()
+{
+ Q_D(QSGText);
+ setMaximumLineCount(INT_MAX);
+ d->elidePos = QPointF();
+ if (d->truncated != false) {
+ d->truncated = false;
+ emit truncatedChanged();
+ }
+}
+
+QSGText::TextFormat QSGText::textFormat() const
+{
+ Q_D(const QSGText);
+ return d->format;
+}
+
+void QSGText::setTextFormat(TextFormat format)
+{
+ Q_D(QSGText);
+ if (format == d->format)
+ return;
+ d->format = format;
+ bool wasRich = d->richText;
+ d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
+
+ if (!wasRich && d->richText && isComponentComplete()) {
+ d->ensureDoc();
+ d->doc->setText(d->text);
+ }
+
+ d->updateLayout();
+
+ emit textFormatChanged(d->format);
+}
+
+QSGText::TextElideMode QSGText::elideMode() const
+{
+ Q_D(const QSGText);
+ return d->elideMode;
+}
+
+void QSGText::setElideMode(QSGText::TextElideMode mode)
+{
+ Q_D(QSGText);
+ if (mode == d->elideMode)
+ return;
+
+ d->elideMode = mode;
+ d->updateLayout();
+
+ emit elideModeChanged(d->elideMode);
+}
+
+/*! \internal */
+QRectF QSGText::boundingRect() const
+{
+ Q_D(const QSGText);
+
+ QRect rect = d->layedOutTextRect;
+ if (d->style != Normal)
+ rect.adjust(-1, 0, 1, 2);
+
+ // Could include font max left/right bearings to either side of rectangle.
+
+ int h = height();
+ switch (d->vAlign) {
+ case AlignTop:
+ break;
+ case AlignBottom:
+ rect.moveTop(h - rect.height());
+ break;
+ case AlignVCenter:
+ rect.moveTop((h - rect.height()) / 2);
+ break;
+ }
+
+ return QRectF(rect);
+}
+
+/*! \internal */
+void QSGText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QSGText);
+ if ((!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width())
+ && (d->wrapMode != QSGText::NoWrap
+ || d->elideMode != QSGText::ElideNone
+ || d->hAlign != QSGText::AlignLeft)) {
+ if ((d->singleline || d->maximumLineCountValid) && d->elideMode != QSGText::ElideNone && widthValid()) {
+ // We need to re-elide
+ d->updateLayout();
+ } else {
+ // We just need to re-layout
+ d->updateSize();
+ }
+ }
+
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+QSGNode *QSGText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+ Q_D(QSGText);
+
+ bool richTextAsImage = false;
+ if (d->richText) {
+ d->ensureDoc();
+ richTextAsImage = QSGTextNode::isComplexRichText(d->doc);
+ }
+
+ QRectF bounds = boundingRect();
+
+ // XXX todo - some styled text can be done by the QSGTextNode
+ if (richTextAsImage || d->cacheAllTextAsImage || (!QSGDistanceFieldGlyphCache::distanceFieldEnabled() && d->style != Normal)) {
+ bool wasDirty = d->imageCacheDirty;
+
+ d->checkImageCache();
+
+ if (d->imageCache.isNull()) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGImageNode *node = 0;
+ if (!oldNode || d->nodeType != QSGTextPrivate::NodeIsTexture) {
+ delete oldNode;
+ node = QSGItemPrivate::get(this)->sceneGraphContext()->createImageNode();
+ d->texture = new QSGPlainTexture();
+ wasDirty = true;
+ d->nodeType = QSGTextPrivate::NodeIsTexture;
+ } else {
+ node = static_cast<QSGImageNode *>(oldNode);
+ Q_ASSERT(d->texture);
+ }
+
+ if (wasDirty) {
+ qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->imageCache.toImage());
+ node->setTexture(0);
+ node->setTexture(d->texture);
+ }
+
+ node->setTargetRect(QRectF(bounds.x(), bounds.y(), d->imageCache.width(), d->imageCache.height()));
+ node->setSourceRect(QRectF(0, 0, 1, 1));
+ node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ node->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that..
+ node->update();
+
+ return node;
+
+ } else {
+ QSGTextNode *node = 0;
+ if (!oldNode || d->nodeType != QSGTextPrivate::NodeIsText) {
+ delete oldNode;
+ node = new QSGTextNode(QSGItemPrivate::get(this)->sceneGraphContext());
+ d->nodeType = QSGTextPrivate::NodeIsText;
+ } else {
+ node = static_cast<QSGTextNode *>(oldNode);
+ }
+
+ node->deleteContent();
+ node->setMatrix(QMatrix4x4());
+
+ if (d->richText) {
+
+ d->ensureDoc();
+ node->addTextDocument(bounds.topLeft(), d->doc, QColor(), d->style, d->styleColor);
+
+ } else {
+ node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor);
+ QMatrix4x4 m;
+ m.translate(0, QFontMetricsF(d->font).ascent());
+ node->setMatrix(m);
+ }
+
+ return node;
+ }
+}
+
+qreal QSGText::paintedWidth() const
+{
+ Q_D(const QSGText);
+ return d->paintedSize.width();
+}
+
+qreal QSGText::paintedHeight() const
+{
+ Q_D(const QSGText);
+ return d->paintedSize.height();
+}
+
+qreal QSGText::lineHeight() const
+{
+ Q_D(const QSGText);
+ return d->lineHeight;
+}
+
+void QSGText::setLineHeight(qreal lineHeight)
+{
+ Q_D(QSGText);
+
+ if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
+ return;
+
+ d->lineHeight = lineHeight;
+ d->updateLayout();
+ emit lineHeightChanged(lineHeight);
+}
+
+QSGText::LineHeightMode QSGText::lineHeightMode() const
+{
+ Q_D(const QSGText);
+ return d->lineHeightMode;
+}
+
+void QSGText::setLineHeightMode(LineHeightMode mode)
+{
+ Q_D(QSGText);
+ if (mode == d->lineHeightMode)
+ return;
+
+ d->lineHeightMode = mode;
+ d->updateLayout();
+
+ emit lineHeightModeChanged(mode);
+}
+
+/*!
+ Returns the number of resources (images) that are being loaded asynchronously.
+*/
+int QSGText::resourcesLoading() const
+{
+ Q_D(const QSGText);
+ return d->doc ? d->doc->resourcesLoading() : 0;
+}
+
+/*! \internal */
+void QSGText::componentComplete()
+{
+ Q_D(QSGText);
+ QSGItem::componentComplete();
+ if (d->updateOnComponentComplete) {
+ d->updateOnComponentComplete = false;
+ if (d->richText) {
+ d->ensureDoc();
+ d->doc->setText(d->text);
+ d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+ } else {
+ d->rightToLeftText = d->text.isRightToLeft();
+ }
+ d->determineHorizontalAlignment();
+ d->updateLayout();
+ }
+}
+
+/*! \internal */
+void QSGText::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGText);
+
+ if (!d->richText || !d->doc || d->doc->documentLayout()->anchorAt(event->pos()).isEmpty()) {
+ event->setAccepted(false);
+ d->activeLink.clear();
+ } else {
+ d->activeLink = d->doc->documentLayout()->anchorAt(event->pos());
+ }
+
+ // ### may malfunction if two of the same links are clicked & dragged onto each other)
+
+ if (!event->isAccepted())
+ QSGItem::mousePressEvent(event);
+
+}
+
+/*! \internal */
+void QSGText::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGText);
+
+ // ### confirm the link, and send a signal out
+ if (d->richText && d->doc && d->activeLink == d->doc->documentLayout()->anchorAt(event->pos()))
+ emit linkActivated(d->activeLink);
+ else
+ event->setAccepted(false);
+
+ if (!event->isAccepted())
+ QSGItem::mouseReleaseEvent(event);
+}
+
+QT_END_NAMESPACE
+
+#include "qsgtext.moc"
diff --git a/src/declarative/items/qsgtext_p.h b/src/declarative/items/qsgtext_p.h
new file mode 100644
index 0000000000..090a2b0e67
--- /dev/null
+++ b/src/declarative/items/qsgtext_p.h
@@ -0,0 +1,214 @@
+// Commit: 27e4302b7f45f22180693d26747f419177c81e27
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXT_P_H
+#define QSGTEXT_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+
+#include <private/qdeclarativeglobal_p.h>
+
+#include <QtGui/qtextoption.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QSGTextPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QSGText : public QSGImplicitSizeItem
+{
+ Q_OBJECT
+ Q_ENUMS(HAlignment)
+ Q_ENUMS(VAlignment)
+ Q_ENUMS(TextStyle)
+ Q_ENUMS(TextFormat)
+ Q_ENUMS(TextElideMode)
+ Q_ENUMS(WrapMode)
+ Q_ENUMS(LineHeightMode)
+
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(TextStyle style READ style WRITE setStyle NOTIFY styleChanged)
+ Q_PROPERTY(QColor styleColor READ styleColor WRITE setStyleColor NOTIFY styleColorChanged)
+ Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged)
+ Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign NOTIFY verticalAlignmentChanged)
+ Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
+ Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged)
+ Q_PROPERTY(bool truncated READ truncated NOTIFY truncatedChanged)
+ Q_PROPERTY(int maximumLineCount READ maximumLineCount WRITE setMaximumLineCount NOTIFY maximumLineCountChanged RESET resetMaximumLineCount)
+
+ Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat NOTIFY textFormatChanged)
+ Q_PROPERTY(TextElideMode elide READ elideMode WRITE setElideMode NOTIFY elideModeChanged) //### elideMode?
+ Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedSizeChanged)
+ Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedSizeChanged)
+ Q_PROPERTY(qreal lineHeight READ lineHeight WRITE setLineHeight NOTIFY lineHeightChanged)
+ Q_PROPERTY(LineHeightMode lineHeightMode READ lineHeightMode WRITE setLineHeightMode NOTIFY lineHeightModeChanged)
+
+public:
+ QSGText(QSGItem *parent=0);
+ ~QSGText();
+
+ enum HAlignment { AlignLeft = Qt::AlignLeft,
+ AlignRight = Qt::AlignRight,
+ AlignHCenter = Qt::AlignHCenter,
+ AlignJustify = Qt::AlignJustify };
+ enum VAlignment { AlignTop = Qt::AlignTop,
+ AlignBottom = Qt::AlignBottom,
+ AlignVCenter = Qt::AlignVCenter };
+ enum TextStyle { Normal,
+ Outline,
+ Raised,
+ Sunken };
+ enum TextFormat { PlainText = Qt::PlainText,
+ RichText = Qt::RichText,
+ AutoText = Qt::AutoText,
+ StyledText = 4 };
+ enum TextElideMode { ElideLeft = Qt::ElideLeft,
+ ElideRight = Qt::ElideRight,
+ ElideMiddle = Qt::ElideMiddle,
+ ElideNone = Qt::ElideNone };
+
+ enum WrapMode { NoWrap = QTextOption::NoWrap,
+ WordWrap = QTextOption::WordWrap,
+ WrapAnywhere = QTextOption::WrapAnywhere,
+ WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT
+ Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere
+ };
+
+ enum LineHeightMode { ProportionalHeight, FixedHeight };
+
+ QString text() const;
+ void setText(const QString &);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QColor color() const;
+ void setColor(const QColor &c);
+
+ TextStyle style() const;
+ void setStyle(TextStyle style);
+
+ QColor styleColor() const;
+ void setStyleColor(const QColor &c);
+
+ HAlignment hAlign() const;
+ void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
+
+ VAlignment vAlign() const;
+ void setVAlign(VAlignment align);
+
+ WrapMode wrapMode() const;
+ void setWrapMode(WrapMode w);
+
+ int lineCount() const;
+ bool truncated() const;
+
+ int maximumLineCount() const;
+ void setMaximumLineCount(int lines);
+ void resetMaximumLineCount();
+
+ TextFormat textFormat() const;
+ void setTextFormat(TextFormat format);
+
+ TextElideMode elideMode() const;
+ void setElideMode(TextElideMode);
+
+ qreal lineHeight() const;
+ void setLineHeight(qreal lineHeight);
+
+ LineHeightMode lineHeightMode() const;
+ void setLineHeightMode(LineHeightMode);
+
+ virtual void componentComplete();
+
+ int resourcesLoading() const; // mainly for testing
+
+ qreal paintedWidth() const;
+ qreal paintedHeight() const;
+
+ QRectF boundingRect() const;
+
+Q_SIGNALS:
+ void textChanged(const QString &text);
+ void linkActivated(const QString &link);
+ void fontChanged(const QFont &font);
+ void colorChanged(const QColor &color);
+ void styleChanged(TextStyle style);
+ void styleColorChanged(const QColor &color);
+ void horizontalAlignmentChanged(HAlignment alignment);
+ void verticalAlignmentChanged(VAlignment alignment);
+ void wrapModeChanged();
+ void lineCountChanged();
+ void truncatedChanged();
+ void maximumLineCountChanged();
+ void textFormatChanged(TextFormat textFormat);
+ void elideModeChanged(TextElideMode mode);
+ void paintedSizeChanged();
+ void lineHeightChanged(qreal lineHeight);
+ void lineHeightModeChanged(LineHeightMode mode);
+ void effectiveHorizontalAlignmentChanged();
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+private:
+ Q_DISABLE_COPY(QSGText)
+ Q_DECLARE_PRIVATE(QSGText)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGText)
+
+QT_END_HEADER
+
+#endif // QSGTEXT_P_H
diff --git a/src/declarative/items/qsgtext_p_p.h b/src/declarative/items/qsgtext_p_p.h
new file mode 100644
index 0000000000..7df91f80d9
--- /dev/null
+++ b/src/declarative/items/qsgtext_p_p.h
@@ -0,0 +1,154 @@
+// Commit: aeb330e3999ef3d7ae8d94b9330471f2a2a13554
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXT_P_P_H
+#define QSGTEXT_P_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 "qsgitem.h"
+#include "qsgimplicitsizeitem_p_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtGui/qtextlayout.h>
+
+#include <private/qdeclarativetextlayout_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTextLayout;
+class QSGTextDocumentWithImageResources;
+class QSGPlainTexture;
+
+class Q_AUTOTEST_EXPORT QSGTextPrivate : public QSGImplicitSizeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGText)
+public:
+ QSGTextPrivate();
+ ~QSGTextPrivate();
+ void init();
+
+ void updateSize();
+ void updateLayout();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QSGText::HAlignment, bool forceAlign = false);
+ void mirrorChange();
+ QTextDocument *textDocument();
+
+ QString text;
+ QFont font;
+ QFont sourceFont;
+ QColor color;
+ QSGText::TextStyle style;
+ QColor styleColor;
+ QString activeLink;
+ QSGText::HAlignment hAlign;
+ QSGText::VAlignment vAlign;
+ QSGText::TextElideMode elideMode;
+ QSGText::TextFormat format;
+ QSGText::WrapMode wrapMode;
+ qreal lineHeight;
+ QSGText::LineHeightMode lineHeightMode;
+ int lineCount;
+ int maximumLineCount;
+ int maximumLineCountValid;
+ QPointF elidePos;
+
+ static QString elideChar;
+
+ void invalidateImageCache();
+ void checkImageCache();
+ QPixmap imageCache;
+ QSGTexture *texture;
+
+ bool imageCacheDirty:1;
+ bool updateOnComponentComplete:1;
+ bool richText:1;
+ bool singleline:1;
+ bool cacheAllTextAsImage:1;
+ bool internalWidthUpdate:1;
+ bool requireImplicitWidth:1;
+ bool truncated:1;
+ bool hAlignImplicit:1;
+ bool rightToLeftText:1;
+
+ QRect layedOutTextRect;
+ QSize paintedSize;
+ qreal naturalWidth;
+ virtual qreal getImplicitWidth() const;
+
+ void ensureDoc();
+ QPixmap textDocumentImage(bool drawStyle);
+ QSGTextDocumentWithImageResources *doc;
+
+ QRect setupTextLayout();
+ QPixmap textLayoutImage(bool drawStyle);
+ void drawTextLayout(QPainter *p, const QPointF &pos, bool drawStyle);
+ QTextLayout layout;
+
+ static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource);
+ static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset);
+
+ static inline QSGTextPrivate *get(QSGText *t) {
+ return t->d_func();
+ }
+
+ enum NodeType {
+ NodeIsNull,
+ NodeIsTexture,
+ NodeIsText,
+ };
+ NodeType nodeType;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXT_P_P_H
diff --git a/src/declarative/items/qsgtextedit.cpp b/src/declarative/items/qsgtextedit.cpp
new file mode 100644
index 0000000000..57f9135917
--- /dev/null
+++ b/src/declarative/items/qsgtextedit.cpp
@@ -0,0 +1,1235 @@
+// Commit: 6980bca15b411f86b9fadb7484a6dd782b9d1403
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtextedit_p.h"
+#include "qsgtextedit_p_p.h"
+#include "qsgevents_p_p.h"
+#include "qsgcanvas.h"
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qtextobject.h>
+#include <QtCore/qmath.h>
+
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qtextcontrol_p.h>
+#include <private/qtextengine_p.h>
+#include <private/qwidget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPrivate *qt_widget_private(QWidget *widget);
+
+QSGTextEdit::QSGTextEdit(QSGItem *parent)
+: QSGImplicitSizePaintedItem(*(new QSGTextEditPrivate), parent)
+{
+ Q_D(QSGTextEdit);
+ d->init();
+}
+
+QString QSGTextEdit::text() const
+{
+ Q_D(const QSGTextEdit);
+
+#ifndef QT_NO_TEXTHTMLPARSER
+ if (d->richText)
+ return d->document->toHtml();
+ else
+#endif
+ return d->document->toPlainText();
+}
+
+void QSGTextEdit::setText(const QString &text)
+{
+ Q_D(QSGTextEdit);
+ if (QSGTextEdit::text() == text)
+ return;
+
+ d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
+ if (d->richText) {
+#ifndef QT_NO_TEXTHTMLPARSER
+ d->control->setHtml(text);
+#else
+ d->control->setPlainText(text);
+#endif
+ } else {
+ d->control->setPlainText(text);
+ }
+ q_textChanged();
+}
+
+QSGTextEdit::TextFormat QSGTextEdit::textFormat() const
+{
+ Q_D(const QSGTextEdit);
+ return d->format;
+}
+
+void QSGTextEdit::setTextFormat(TextFormat format)
+{
+ Q_D(QSGTextEdit);
+ if (format == d->format)
+ return;
+ bool wasRich = d->richText;
+ d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
+
+ if (wasRich && !d->richText) {
+ d->control->setPlainText(d->text);
+ updateSize();
+ } else if (!wasRich && d->richText) {
+#ifndef QT_NO_TEXTHTMLPARSER
+ d->control->setHtml(d->text);
+#else
+ d->control->setPlainText(d->text);
+#endif
+ updateSize();
+ }
+ d->format = format;
+ d->control->setAcceptRichText(d->format != PlainText);
+ emit textFormatChanged(d->format);
+}
+
+QFont QSGTextEdit::font() const
+{
+ Q_D(const QSGTextEdit);
+ return d->sourceFont;
+}
+
+void QSGTextEdit::setFont(const QFont &font)
+{
+ Q_D(QSGTextEdit);
+ if (d->sourceFont == font)
+ return;
+
+ d->sourceFont = font;
+ QFont oldFont = d->font;
+ d->font = font;
+ if (d->font.pointSizeF() != -1) {
+ // 0.5pt resolution
+ qreal size = qRound(d->font.pointSizeF()*2.0);
+ d->font.setPointSizeF(size/2.0);
+ }
+
+ if (oldFont != d->font) {
+ d->document->setDefaultFont(d->font);
+ if(d->cursor){
+ d->cursor->setHeight(QFontMetrics(d->font).height());
+ moveCursorDelegate();
+ }
+ updateSize();
+ update();
+ }
+ emit fontChanged(d->sourceFont);
+}
+
+QColor QSGTextEdit::color() const
+{
+ Q_D(const QSGTextEdit);
+ return d->color;
+}
+
+void QSGTextEdit::setColor(const QColor &color)
+{
+ Q_D(QSGTextEdit);
+ if (d->color == color)
+ return;
+
+ d->color = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::Text, color);
+ d->control->setPalette(pal);
+ update();
+ emit colorChanged(d->color);
+}
+
+QColor QSGTextEdit::selectionColor() const
+{
+ Q_D(const QSGTextEdit);
+ return d->selectionColor;
+}
+
+void QSGTextEdit::setSelectionColor(const QColor &color)
+{
+ Q_D(QSGTextEdit);
+ if (d->selectionColor == color)
+ return;
+
+ d->selectionColor = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::Highlight, color);
+ d->control->setPalette(pal);
+ update();
+ emit selectionColorChanged(d->selectionColor);
+}
+
+QColor QSGTextEdit::selectedTextColor() const
+{
+ Q_D(const QSGTextEdit);
+ return d->selectedTextColor;
+}
+
+void QSGTextEdit::setSelectedTextColor(const QColor &color)
+{
+ Q_D(QSGTextEdit);
+ if (d->selectedTextColor == color)
+ return;
+
+ d->selectedTextColor = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::HighlightedText, color);
+ d->control->setPalette(pal);
+ update();
+ emit selectedTextColorChanged(d->selectedTextColor);
+}
+
+QSGTextEdit::HAlignment QSGTextEdit::hAlign() const
+{
+ Q_D(const QSGTextEdit);
+ return d->hAlign;
+}
+
+void QSGTextEdit::setHAlign(HAlignment align)
+{
+ Q_D(QSGTextEdit);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
+ d->updateDefaultTextOption();
+ updateSize();
+ }
+}
+
+void QSGTextEdit::resetHAlign()
+{
+ Q_D(QSGTextEdit);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete()) {
+ d->updateDefaultTextOption();
+ updateSize();
+ }
+}
+
+QSGTextEdit::HAlignment QSGTextEdit::effectiveHAlign() const
+{
+ Q_D(const QSGTextEdit);
+ QSGTextEdit::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QSGTextEdit::AlignLeft:
+ effectiveAlignment = QSGTextEdit::AlignRight;
+ break;
+ case QSGTextEdit::AlignRight:
+ effectiveAlignment = QSGTextEdit::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QSGTextEditPrivate::setHAlign(QSGTextEdit::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QSGTextEdit);
+ if (hAlign != alignment || forceAlign) {
+ QSGTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+ emit q->horizontalAlignmentChanged(alignment);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QSGTextEditPrivate::determineHorizontalAlignment()
+{
+ Q_Q(QSGTextEdit);
+ if (hAlignImplicit && q->isComponentComplete()) {
+ bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
+ return setHAlign(alignToRight ? QSGTextEdit::AlignRight : QSGTextEdit::AlignLeft);
+ }
+ return false;
+}
+
+void QSGTextEditPrivate::mirrorChange()
+{
+ Q_Q(QSGTextEdit);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QSGTextEdit::AlignRight || hAlign == QSGTextEdit::AlignLeft)) {
+ updateDefaultTextOption();
+ q->updateSize();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+QSGTextEdit::VAlignment QSGTextEdit::vAlign() const
+{
+ Q_D(const QSGTextEdit);
+ return d->vAlign;
+}
+
+void QSGTextEdit::setVAlign(QSGTextEdit::VAlignment alignment)
+{
+ Q_D(QSGTextEdit);
+ if (alignment == d->vAlign)
+ return;
+ d->vAlign = alignment;
+ d->updateDefaultTextOption();
+ updateSize();
+ emit verticalAlignmentChanged(d->vAlign);
+}
+
+QSGTextEdit::WrapMode QSGTextEdit::wrapMode() const
+{
+ Q_D(const QSGTextEdit);
+ return d->wrapMode;
+}
+
+void QSGTextEdit::setWrapMode(WrapMode mode)
+{
+ Q_D(QSGTextEdit);
+ if (mode == d->wrapMode)
+ return;
+ d->wrapMode = mode;
+ d->updateDefaultTextOption();
+ updateSize();
+ emit wrapModeChanged();
+}
+
+int QSGTextEdit::lineCount() const
+{
+ Q_D(const QSGTextEdit);
+ return d->lineCount;
+}
+
+qreal QSGTextEdit::paintedWidth() const
+{
+ Q_D(const QSGTextEdit);
+ return d->paintedSize.width();
+}
+
+qreal QSGTextEdit::paintedHeight() const
+{
+ Q_D(const QSGTextEdit);
+ return d->paintedSize.height();
+}
+
+QRectF QSGTextEdit::positionToRectangle(int pos) const
+{
+ Q_D(const QSGTextEdit);
+ QTextCursor c(d->document);
+ c.setPosition(pos);
+ return d->control->cursorRect(c);
+
+}
+
+int QSGTextEdit::positionAt(int x, int y) const
+{
+ Q_D(const QSGTextEdit);
+ int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
+ QTextCursor cursor = d->control->textCursor();
+ if (r > cursor.position()) {
+ // The cursor position includes positions within the preedit text, but only positions in the
+ // same text block are offset so it is possible to get a position that is either part of the
+ // preedit or the next text block.
+ QTextLayout *layout = cursor.block().layout();
+ const int preeditLength = layout
+ ? layout->preeditAreaText().length()
+ : 0;
+ if (preeditLength > 0
+ && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
+ r = r > cursor.position() + preeditLength
+ ? r - preeditLength
+ : cursor.position();
+ }
+ }
+ return r;
+}
+
+void QSGTextEdit::moveCursorSelection(int pos)
+{
+ //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
+ Q_D(QSGTextEdit);
+ QTextCursor cursor = d->control->textCursor();
+ if (cursor.position() == pos)
+ return;
+ cursor.setPosition(pos, QTextCursor::KeepAnchor);
+ d->control->setTextCursor(cursor);
+}
+
+void QSGTextEdit::moveCursorSelection(int pos, SelectionMode mode)
+{
+ Q_D(QSGTextEdit);
+ QTextCursor cursor = d->control->textCursor();
+ if (cursor.position() == pos)
+ return;
+ if (mode == SelectCharacters) {
+ cursor.setPosition(pos, QTextCursor::KeepAnchor);
+ } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
+ if (cursor.anchor() > cursor.position()) {
+ cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
+ if (cursor.position() == cursor.anchor())
+ cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
+ else
+ cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
+ } else {
+ cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
+ }
+
+ cursor.setPosition(pos, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
+ if (cursor.position() != pos)
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+ } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
+ if (cursor.anchor() < cursor.position()) {
+ cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
+ } else {
+ cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+ if (cursor.position() != cursor.anchor()) {
+ cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
+ }
+ }
+
+ cursor.setPosition(pos, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+ if (cursor.position() != pos) {
+ cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
+ }
+ }
+ d->control->setTextCursor(cursor);
+}
+
+bool QSGTextEdit::isCursorVisible() const
+{
+ Q_D(const QSGTextEdit);
+ return d->cursorVisible;
+}
+
+void QSGTextEdit::setCursorVisible(bool on)
+{
+ Q_D(QSGTextEdit);
+ if (d->cursorVisible == on)
+ return;
+ d->cursorVisible = on;
+ QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
+ if (!on && !d->persistentSelection)
+ d->control->setCursorIsFocusIndicator(true);
+ d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
+ emit cursorVisibleChanged(d->cursorVisible);
+}
+
+int QSGTextEdit::cursorPosition() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->textCursor().position();
+}
+
+void QSGTextEdit::setCursorPosition(int pos)
+{
+ Q_D(QSGTextEdit);
+ if (pos < 0 || pos > d->text.length())
+ return;
+ QTextCursor cursor = d->control->textCursor();
+ if (cursor.position() == pos && cursor.anchor() == pos)
+ return;
+ cursor.setPosition(pos);
+ d->control->setTextCursor(cursor);
+}
+
+QDeclarativeComponent* QSGTextEdit::cursorDelegate() const
+{
+ Q_D(const QSGTextEdit);
+ return d->cursorComponent;
+}
+
+void QSGTextEdit::setCursorDelegate(QDeclarativeComponent* c)
+{
+ Q_D(QSGTextEdit);
+ if(d->cursorComponent){
+ if(d->cursor){
+ disconnect(d->control, SIGNAL(cursorPositionChanged()),
+ this, SLOT(moveCursorDelegate()));
+ d->control->setCursorWidth(-1);
+ update(cursorRectangle());
+ delete d->cursor;
+ d->cursor = 0;
+ }
+ }
+ d->cursorComponent = c;
+ if(c && c->isReady()){
+ loadCursorDelegate();
+ }else{
+ if(c)
+ connect(c, SIGNAL(statusChanged()),
+ this, SLOT(loadCursorDelegate()));
+ }
+
+ emit cursorDelegateChanged();
+}
+
+void QSGTextEdit::loadCursorDelegate()
+{
+ Q_D(QSGTextEdit);
+ if(d->cursorComponent->isLoading())
+ return;
+ d->cursor = qobject_cast<QSGItem*>(d->cursorComponent->create(qmlContext(this)));
+ if(d->cursor){
+ connect(d->control, SIGNAL(cursorPositionChanged()),
+ this, SLOT(moveCursorDelegate()));
+ d->control->setCursorWidth(0);
+ update(cursorRectangle());
+ QDeclarative_setParent_noEvent(d->cursor, this);
+ d->cursor->setParentItem(this);
+ d->cursor->setHeight(QFontMetrics(d->font).height());
+ moveCursorDelegate();
+ }else{
+ qmlInfo(this) << "Error loading cursor delegate.";
+ }
+}
+
+int QSGTextEdit::selectionStart() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->textCursor().selectionStart();
+}
+
+int QSGTextEdit::selectionEnd() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->textCursor().selectionEnd();
+}
+
+QString QSGTextEdit::selectedText() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->textCursor().selectedText();
+}
+
+bool QSGTextEdit::focusOnPress() const
+{
+ Q_D(const QSGTextEdit);
+ return d->focusOnPress;
+}
+
+void QSGTextEdit::setFocusOnPress(bool on)
+{
+ Q_D(QSGTextEdit);
+ if (d->focusOnPress == on)
+ return;
+ d->focusOnPress = on;
+ emit activeFocusOnPressChanged(d->focusOnPress);
+}
+
+bool QSGTextEdit::persistentSelection() const
+{
+ Q_D(const QSGTextEdit);
+ return d->persistentSelection;
+}
+
+void QSGTextEdit::setPersistentSelection(bool on)
+{
+ Q_D(QSGTextEdit);
+ if (d->persistentSelection == on)
+ return;
+ d->persistentSelection = on;
+ emit persistentSelectionChanged(d->persistentSelection);
+}
+
+qreal QSGTextEdit::textMargin() const
+{
+ Q_D(const QSGTextEdit);
+ return d->textMargin;
+}
+
+void QSGTextEdit::setTextMargin(qreal margin)
+{
+ Q_D(QSGTextEdit);
+ if (d->textMargin == margin)
+ return;
+ d->textMargin = margin;
+ d->document->setDocumentMargin(d->textMargin);
+ emit textMarginChanged(d->textMargin);
+}
+
+void QSGTextEdit::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ if (newGeometry.width() != oldGeometry.width())
+ updateSize();
+ QSGPaintedItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+void QSGTextEdit::componentComplete()
+{
+ Q_D(QSGTextEdit);
+ QSGPaintedItem::componentComplete();
+ if (d->dirty) {
+ d->determineHorizontalAlignment();
+ d->updateDefaultTextOption();
+ updateSize();
+ d->dirty = false;
+ }
+}
+
+bool QSGTextEdit::selectByMouse() const
+{
+ Q_D(const QSGTextEdit);
+ return d->selectByMouse;
+}
+
+void QSGTextEdit::setSelectByMouse(bool on)
+{
+ Q_D(QSGTextEdit);
+ if (d->selectByMouse != on) {
+ d->selectByMouse = on;
+ setKeepMouseGrab(on);
+ if (on)
+ setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
+ else
+ setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
+ emit selectByMouseChanged(on);
+ }
+}
+
+QSGTextEdit::SelectionMode QSGTextEdit::mouseSelectionMode() const
+{
+ Q_D(const QSGTextEdit);
+ return d->mouseSelectionMode;
+}
+
+void QSGTextEdit::setMouseSelectionMode(SelectionMode mode)
+{
+ Q_D(QSGTextEdit);
+ if (d->mouseSelectionMode != mode) {
+ d->mouseSelectionMode = mode;
+ d->control->setWordSelectionEnabled(mode == SelectWords);
+ emit mouseSelectionModeChanged(mode);
+ }
+}
+
+void QSGTextEdit::setReadOnly(bool r)
+{
+ Q_D(QSGTextEdit);
+ if (r == isReadOnly())
+ return;
+
+ setFlag(QSGItem::ItemAcceptsInputMethod, !r);
+ Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
+ if (d->selectByMouse)
+ flags = flags | Qt::TextSelectableByMouse;
+ if (!r)
+ flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
+ d->control->setTextInteractionFlags(flags);
+ if (!r)
+ d->control->moveCursor(QTextCursor::End);
+
+ emit readOnlyChanged(r);
+}
+
+bool QSGTextEdit::isReadOnly() const
+{
+ Q_D(const QSGTextEdit);
+ return !(d->control->textInteractionFlags() & Qt::TextEditable);
+}
+
+void QSGTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
+{
+ Q_D(QSGTextEdit);
+ d->control->setTextInteractionFlags(flags);
+}
+
+Qt::TextInteractionFlags QSGTextEdit::textInteractionFlags() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->textInteractionFlags();
+}
+
+QRect QSGTextEdit::cursorRectangle() const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->cursorRect().toRect().translated(0,-d->yoff);
+}
+
+bool QSGTextEdit::event(QEvent *event)
+{
+ Q_D(QSGTextEdit);
+ if (event->type() == QEvent::ShortcutOverride) {
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ return event->isAccepted();
+ }
+ return QSGPaintedItem::event(event);
+}
+
+/*!
+\overload
+Handles the given key \a event.
+*/
+void QSGTextEdit::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QSGTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QSGPaintedItem::keyPressEvent(event);
+}
+
+/*!
+\overload
+Handles the given key \a event.
+*/
+void QSGTextEdit::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QSGTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QSGPaintedItem::keyReleaseEvent(event);
+}
+
+void QSGTextEdit::deselect()
+{
+ Q_D(QSGTextEdit);
+ QTextCursor c = d->control->textCursor();
+ c.clearSelection();
+ d->control->setTextCursor(c);
+}
+
+void QSGTextEdit::selectAll()
+{
+ Q_D(QSGTextEdit);
+ d->control->selectAll();
+}
+
+void QSGTextEdit::selectWord()
+{
+ Q_D(QSGTextEdit);
+ QTextCursor c = d->control->textCursor();
+ c.select(QTextCursor::WordUnderCursor);
+ d->control->setTextCursor(c);
+}
+
+void QSGTextEdit::select(int start, int end)
+{
+ Q_D(QSGTextEdit);
+ if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
+ return;
+ QTextCursor cursor = d->control->textCursor();
+ cursor.beginEditBlock();
+ cursor.setPosition(start, QTextCursor::MoveAnchor);
+ cursor.setPosition(end, QTextCursor::KeepAnchor);
+ cursor.endEditBlock();
+ d->control->setTextCursor(cursor);
+
+ // QTBUG-11100
+ updateSelectionMarkers();
+}
+
+bool QSGTextEdit::isRightToLeft(int start, int end)
+{
+ Q_D(QSGTextEdit);
+ if (start > end) {
+ qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
+ return false;
+ } else {
+ return d->text.mid(start, end - start).isRightToLeft();
+ }
+}
+
+#ifndef QT_NO_CLIPBOARD
+void QSGTextEdit::cut()
+{
+ Q_D(QSGTextEdit);
+ d->control->cut();
+}
+
+void QSGTextEdit::copy()
+{
+ Q_D(QSGTextEdit);
+ d->control->copy();
+}
+
+void QSGTextEdit::paste()
+{
+ Q_D(QSGTextEdit);
+ d->control->paste();
+}
+#endif // QT_NO_CLIPBOARD
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QSGTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextEdit);
+ if (d->focusOnPress){
+ bool hadActiveFocus = hasActiveFocus();
+ forceActiveFocus();
+ if (d->showInputPanelOnFocus) {
+ if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
+ // re-open input panel on press if already focused
+ openSoftwareInputPanel();
+ }
+ } else { // show input panel on click
+ if (hasActiveFocus() && !hadActiveFocus) {
+ d->clickCausedFocus = true;
+ }
+ }
+ }
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QSGPaintedItem::mousePressEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QSGTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!d->showInputPanelOnFocus) { // input panel on click
+ if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ qt_widget_private(canvas())->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
+ }
+ }
+ }
+ d->clickCausedFocus = false;
+
+ if (!event->isAccepted())
+ QSGPaintedItem::mouseReleaseEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QSGTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QSGPaintedItem::mouseDoubleClickEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QSGTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QSGPaintedItem::mouseMoveEvent(event);
+}
+
+/*!
+\overload
+Handles the given input method \a event.
+*/
+void QSGTextEdit::inputMethodEvent(QInputMethodEvent *event)
+{
+ Q_D(QSGTextEdit);
+ const bool wasComposing = isInputMethodComposing();
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (wasComposing != isInputMethodComposing())
+ emit inputMethodComposingChanged();
+}
+
+void QSGTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QSGTextEdit);
+ if (change == ItemActiveFocusHasChanged) {
+ setCursorVisible(value.boolValue && d->canvas && d->canvas->hasFocus());
+ }
+ QSGItem::itemChange(change, value);
+}
+
+/*!
+\overload
+Returns the value of the given \a property.
+*/
+QVariant QSGTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QSGTextEdit);
+ return d->control->inputMethodQuery(property);
+}
+
+/*!
+Draws the contents of the text edit using the given \a painter within
+the given \a bounds.
+*/
+void QSGTextEdit::paint(QPainter *painter)
+{
+ // XXX todo
+ QRect bounds(0, 0, width(), height());
+ Q_D(QSGTextEdit);
+
+ painter->setRenderHint(QPainter::TextAntialiasing, true);
+ painter->translate(0,d->yoff);
+
+ d->control->drawContents(painter, bounds.translated(0,-d->yoff));
+
+ painter->translate(0,-d->yoff);
+}
+
+void QSGTextEdit::updateImgCache(const QRectF &rf)
+{
+ Q_D(const QSGTextEdit);
+ QRect r;
+ if (!rf.isValid()) {
+ r = QRect(0,0,INT_MAX,INT_MAX);
+ } else {
+ r = rf.toRect();
+ if (r.height() > INT_MAX/2) {
+ // Take care of overflow when translating "everything"
+ r.setTop(r.y() + d->yoff);
+ r.setBottom(INT_MAX/2);
+ } else {
+ r = r.translated(0,d->yoff);
+ }
+ }
+ update(r);
+}
+
+bool QSGTextEdit::canPaste() const
+{
+ Q_D(const QSGTextEdit);
+ return d->canPaste;
+}
+
+bool QSGTextEdit::isInputMethodComposing() const
+{
+ Q_D(const QSGTextEdit);
+ if (QTextLayout *layout = d->control->textCursor().block().layout())
+ return layout->preeditAreaText().length() > 0;
+ return false;
+}
+
+void QSGTextEditPrivate::init()
+{
+ Q_Q(QSGTextEdit);
+
+ q->setSmooth(smooth);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QSGItem::ItemAcceptsInputMethod);
+
+ control = new QTextControl(q);
+ control->setIgnoreUnusedNavigationEvents(true);
+ control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
+ control->setDragEnabled(false);
+
+ // QTextControl follows the default text color
+ // defined by the platform, declarative text
+ // should be black by default
+ QPalette pal = control->palette();
+ if (pal.color(QPalette::Text) != color) {
+ pal.setColor(QPalette::Text, color);
+ control->setPalette(pal);
+ }
+
+ QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
+
+ QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
+ QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
+ QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
+ QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
+ QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
+ QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorRectangleChanged()));
+ QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
+#ifndef QT_NO_CLIPBOARD
+ QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
+ QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
+ canPaste = control->canPaste();
+#endif
+
+ document = control->document();
+ document->setDefaultFont(font);
+ document->setDocumentMargin(textMargin);
+ document->setUndoRedoEnabled(false); // flush undo buffer.
+ document->setUndoRedoEnabled(true);
+ updateDefaultTextOption();
+}
+
+void QSGTextEdit::q_textChanged()
+{
+ Q_D(QSGTextEdit);
+ d->text = text();
+ d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
+ d->determineHorizontalAlignment();
+ d->updateDefaultTextOption();
+ updateSize();
+ updateTotalLines();
+ updateMicroFocus();
+ emit textChanged(d->text);
+}
+
+void QSGTextEdit::moveCursorDelegate()
+{
+ Q_D(QSGTextEdit);
+ if(!d->cursor)
+ return;
+ QRectF cursorRect = d->control->cursorRect();
+ d->cursor->setX(cursorRect.x());
+ d->cursor->setY(cursorRect.y());
+}
+
+void QSGTextEditPrivate::updateSelection()
+{
+ Q_Q(QSGTextEdit);
+ QTextCursor cursor = control->textCursor();
+ bool startChange = (lastSelectionStart != cursor.selectionStart());
+ bool endChange = (lastSelectionEnd != cursor.selectionEnd());
+ cursor.beginEditBlock();
+ cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
+ cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
+ cursor.endEditBlock();
+ control->setTextCursor(cursor);
+ if(startChange)
+ q->selectionStartChanged();
+ if(endChange)
+ q->selectionEndChanged();
+}
+
+void QSGTextEdit::updateSelectionMarkers()
+{
+ Q_D(QSGTextEdit);
+ if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
+ d->lastSelectionStart = d->control->textCursor().selectionStart();
+ emit selectionStartChanged();
+ }
+ if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
+ d->lastSelectionEnd = d->control->textCursor().selectionEnd();
+ emit selectionEndChanged();
+ }
+ updateMicroFocus();
+}
+
+QRectF QSGTextEdit::boundingRect() const
+{
+ Q_D(const QSGTextEdit);
+ QRectF r = QSGPaintedItem::boundingRect();
+ int cursorWidth = 1;
+ if(d->cursor)
+ cursorWidth = d->cursor->width();
+ if(!d->document->isEmpty())
+ cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
+
+ // Could include font max left/right bearings to either side of rectangle.
+
+ r.setRight(r.right() + cursorWidth);
+ return r.translated(0,d->yoff);
+}
+
+qreal QSGTextEditPrivate::getImplicitWidth() const
+{
+ Q_Q(const QSGTextEdit);
+ if (!requireImplicitWidth) {
+ // We don't calculate implicitWidth unless it is required.
+ // We need to force a size update now to ensure implicitWidth is calculated
+ const_cast<QSGTextEditPrivate*>(this)->requireImplicitWidth = true;
+ const_cast<QSGTextEdit*>(q)->updateSize();
+ }
+ return implicitWidth;
+}
+
+//### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
+// need to do all the calculations each time
+void QSGTextEdit::updateSize()
+{
+ Q_D(QSGTextEdit);
+ if (isComponentComplete()) {
+ qreal naturalWidth = d->implicitWidth;
+ // ### assumes that if the width is set, the text will fill to edges
+ // ### (unless wrap is false, then clipping will occur)
+ if (widthValid()) {
+ if (!d->requireImplicitWidth) {
+ emit implicitWidthChanged();
+ // if the implicitWidth is used, then updateSize() has already been called (recursively)
+ if (d->requireImplicitWidth)
+ return;
+ }
+ if (d->requireImplicitWidth) {
+ d->document->setTextWidth(-1);
+ naturalWidth = d->document->idealWidth();
+ }
+ if (d->document->textWidth() != width())
+ d->document->setTextWidth(width());
+ } else {
+ d->document->setTextWidth(-1);
+ }
+ QFontMetrics fm = QFontMetrics(d->font);
+ int dy = height();
+ dy -= (int)d->document->size().height();
+
+ int nyoff;
+ if (heightValid()) {
+ if (d->vAlign == AlignBottom)
+ nyoff = dy;
+ else if (d->vAlign == AlignVCenter)
+ nyoff = dy/2;
+ else
+ nyoff = 0;
+ } else {
+ nyoff = 0;
+ }
+ if (nyoff != d->yoff)
+ d->yoff = nyoff;
+ setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
+
+ //### need to comfirm cost of always setting these
+ int newWidth = qCeil(d->document->idealWidth());
+ if (!widthValid() && d->document->textWidth() != newWidth)
+ d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
+ // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
+ if (!widthValid())
+ setImplicitWidth(newWidth);
+ else if (d->requireImplicitWidth)
+ setImplicitWidth(naturalWidth);
+ qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
+ setImplicitHeight(newHeight);
+
+ d->paintedSize = QSize(newWidth, newHeight);
+ setContentsSize(d->paintedSize);
+ emit paintedSizeChanged();
+ } else {
+ d->dirty = true;
+ }
+ update();
+}
+
+void QSGTextEdit::updateTotalLines()
+{
+ Q_D(QSGTextEdit);
+
+ int subLines = 0;
+
+ for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
+ QTextLayout *layout = it.layout();
+ if (!layout)
+ continue;
+ subLines += layout->lineCount()-1;
+ }
+
+ int newTotalLines = d->document->lineCount() + subLines;
+ if (d->lineCount != newTotalLines) {
+ d->lineCount = newTotalLines;
+ emit lineCountChanged();
+ }
+}
+
+void QSGTextEditPrivate::updateDefaultTextOption()
+{
+ Q_Q(QSGTextEdit);
+ QTextOption opt = document->defaultTextOption();
+ int oldAlignment = opt.alignment();
+
+ QSGTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
+ if (rightToLeftText) {
+ if (horizontalAlignment == QSGTextEdit::AlignLeft)
+ horizontalAlignment = QSGTextEdit::AlignRight;
+ else if (horizontalAlignment == QSGTextEdit::AlignRight)
+ horizontalAlignment = QSGTextEdit::AlignLeft;
+ }
+ opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
+
+ QTextOption::WrapMode oldWrapMode = opt.wrapMode();
+ opt.setWrapMode(QTextOption::WrapMode(wrapMode));
+
+ if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
+ return;
+ document->setDefaultTextOption(opt);
+}
+
+
+void QSGTextEdit::openSoftwareInputPanel()
+{
+ if (qApp) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ QEvent event(QEvent::RequestSoftwareInputPanel);
+ QApplication::sendEvent(canvas(), &event);
+ }
+ }
+}
+
+void QSGTextEdit::closeSoftwareInputPanel()
+{
+ if (qApp) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ QEvent event(QEvent::CloseSoftwareInputPanel);
+ QApplication::sendEvent(canvas(), &event);
+ }
+ }
+}
+
+void QSGTextEdit::focusInEvent(QFocusEvent *event)
+{
+ Q_D(const QSGTextEdit);
+ if (d->showInputPanelOnFocus) {
+ if (d->focusOnPress && !isReadOnly()) {
+ openSoftwareInputPanel();
+ }
+ }
+ QSGPaintedItem::focusInEvent(event);
+}
+
+void QSGTextEdit::q_canPasteChanged()
+{
+ Q_D(QSGTextEdit);
+ bool old = d->canPaste;
+ d->canPaste = d->control->canPaste();
+ if(old!=d->canPaste)
+ emit canPasteChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgtextedit_p.h b/src/declarative/items/qsgtextedit_p.h
new file mode 100644
index 0000000000..547ead18e9
--- /dev/null
+++ b/src/declarative/items/qsgtextedit_p.h
@@ -0,0 +1,303 @@
+// Commit: 27e4302b7f45f22180693d26747f419177c81e27
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTEDIT_P_H
+#define QSGTEXTEDIT_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+
+#include <QtGui/qtextoption.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTextEditPrivate;
+class Q_AUTOTEST_EXPORT QSGTextEdit : public QSGImplicitSizePaintedItem
+{
+ Q_OBJECT
+ Q_ENUMS(VAlignment)
+ Q_ENUMS(HAlignment)
+ Q_ENUMS(TextFormat)
+ Q_ENUMS(WrapMode)
+ Q_ENUMS(SelectionMode)
+
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor NOTIFY selectionColorChanged)
+ Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor NOTIFY selectedTextColorChanged)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
+ Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged)
+ Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign NOTIFY verticalAlignmentChanged)
+ Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
+ Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged)
+ Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedSizeChanged)
+ Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedSizeChanged)
+ Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat NOTIFY textFormatChanged)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged)
+ Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible NOTIFY cursorVisibleChanged)
+ Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
+ Q_PROPERTY(QRect cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged)
+ Q_PROPERTY(QDeclarativeComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged)
+ Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged)
+ Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged)
+ Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectionChanged)
+ Q_PROPERTY(bool activeFocusOnPress READ focusOnPress WRITE setFocusOnPress NOTIFY activeFocusOnPressChanged)
+ Q_PROPERTY(bool persistentSelection READ persistentSelection WRITE setPersistentSelection NOTIFY persistentSelectionChanged)
+ Q_PROPERTY(qreal textMargin READ textMargin WRITE setTextMargin NOTIFY textMarginChanged)
+ Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints)
+ Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged)
+ Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged)
+ Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged)
+ Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged)
+
+public:
+ QSGTextEdit(QSGItem *parent=0);
+
+ enum HAlignment {
+ AlignLeft = Qt::AlignLeft,
+ AlignRight = Qt::AlignRight,
+ AlignHCenter = Qt::AlignHCenter,
+ AlignJustify = Qt::AlignJustify
+ };
+
+ enum VAlignment {
+ AlignTop = Qt::AlignTop,
+ AlignBottom = Qt::AlignBottom,
+ AlignVCenter = Qt::AlignVCenter
+ };
+
+ enum TextFormat {
+ PlainText = Qt::PlainText,
+ RichText = Qt::RichText,
+ AutoText = Qt::AutoText
+ };
+
+ enum WrapMode { NoWrap = QTextOption::NoWrap,
+ WordWrap = QTextOption::WordWrap,
+ WrapAnywhere = QTextOption::WrapAnywhere,
+ WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT
+ Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere
+ };
+
+ enum SelectionMode {
+ SelectCharacters,
+ SelectWords
+ };
+
+ Q_INVOKABLE void openSoftwareInputPanel();
+ Q_INVOKABLE void closeSoftwareInputPanel();
+
+ QString text() const;
+ void setText(const QString &);
+
+ TextFormat textFormat() const;
+ void setTextFormat(TextFormat format);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QColor color() const;
+ void setColor(const QColor &c);
+
+ QColor selectionColor() const;
+ void setSelectionColor(const QColor &c);
+
+ QColor selectedTextColor() const;
+ void setSelectedTextColor(const QColor &c);
+
+ HAlignment hAlign() const;
+ void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
+
+ VAlignment vAlign() const;
+ void setVAlign(VAlignment align);
+
+ WrapMode wrapMode() const;
+ void setWrapMode(WrapMode w);
+
+ int lineCount() const;
+
+ bool isCursorVisible() const;
+ void setCursorVisible(bool on);
+
+ int cursorPosition() const;
+ void setCursorPosition(int pos);
+
+ QDeclarativeComponent* cursorDelegate() const;
+ void setCursorDelegate(QDeclarativeComponent*);
+
+ int selectionStart() const;
+ int selectionEnd() const;
+
+ QString selectedText() const;
+
+ bool focusOnPress() const;
+ void setFocusOnPress(bool on);
+
+ bool persistentSelection() const;
+ void setPersistentSelection(bool on);
+
+ qreal textMargin() const;
+ void setTextMargin(qreal margin);
+
+ bool selectByMouse() const;
+ void setSelectByMouse(bool);
+
+ SelectionMode mouseSelectionMode() const;
+ void setMouseSelectionMode(SelectionMode mode);
+
+ bool canPaste() const;
+
+ virtual void componentComplete();
+
+ /* FROM EDIT */
+ void setReadOnly(bool);
+ bool isReadOnly() const;
+
+ void setTextInteractionFlags(Qt::TextInteractionFlags flags);
+ Qt::TextInteractionFlags textInteractionFlags() const;
+
+ QRect cursorRectangle() const;
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+
+ qreal paintedWidth() const;
+ qreal paintedHeight() const;
+
+ Q_INVOKABLE QRectF positionToRectangle(int) const;
+ Q_INVOKABLE int positionAt(int x, int y) const;
+ Q_INVOKABLE void moveCursorSelection(int pos);
+ Q_INVOKABLE void moveCursorSelection(int pos, SelectionMode mode);
+
+ QRectF boundingRect() const;
+
+ bool isInputMethodComposing() const;
+
+Q_SIGNALS:
+ void textChanged(const QString &);
+ void paintedSizeChanged();
+ void cursorPositionChanged();
+ void cursorRectangleChanged();
+ void selectionStartChanged();
+ void selectionEndChanged();
+ void selectionChanged();
+ void colorChanged(const QColor &color);
+ void selectionColorChanged(const QColor &color);
+ void selectedTextColorChanged(const QColor &color);
+ void fontChanged(const QFont &font);
+ void horizontalAlignmentChanged(HAlignment alignment);
+ void verticalAlignmentChanged(VAlignment alignment);
+ void wrapModeChanged();
+ void lineCountChanged();
+ void textFormatChanged(TextFormat textFormat);
+ void readOnlyChanged(bool isReadOnly);
+ void cursorVisibleChanged(bool isCursorVisible);
+ void cursorDelegateChanged();
+ void activeFocusOnPressChanged(bool activeFocusOnPressed);
+ void persistentSelectionChanged(bool isPersistentSelection);
+ void textMarginChanged(qreal textMargin);
+ void selectByMouseChanged(bool selectByMouse);
+ void mouseSelectionModeChanged(SelectionMode mode);
+ void linkActivated(const QString &link);
+ void canPasteChanged();
+ void inputMethodComposingChanged();
+ void effectiveHorizontalAlignmentChanged();
+
+public Q_SLOTS:
+ void selectAll();
+ void selectWord();
+ void select(int start, int end);
+ void deselect();
+ bool isRightToLeft(int start, int end);
+#ifndef QT_NO_CLIPBOARD
+ void cut();
+ void copy();
+ void paste();
+#endif
+
+private Q_SLOTS:
+ void updateImgCache(const QRectF &rect);
+ void q_textChanged();
+ void updateSelectionMarkers();
+ void moveCursorDelegate();
+ void loadCursorDelegate();
+ void q_canPasteChanged();
+
+private:
+ void updateSize();
+ void updateTotalLines();
+
+protected:
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+ bool event(QEvent *);
+ void keyPressEvent(QKeyEvent *);
+ void keyReleaseEvent(QKeyEvent *);
+ void focusInEvent(QFocusEvent *event);
+
+ // mouse filter?
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void inputMethodEvent(QInputMethodEvent *e);
+ virtual void itemChange(ItemChange, const ItemChangeData &);
+
+ void paint(QPainter *);
+private:
+ Q_DISABLE_COPY(QSGTextEdit)
+ Q_DECLARE_PRIVATE(QSGTextEdit)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGTextEdit)
+
+QT_END_HEADER
+
+#endif // QSGTEXTEDIT_P_H
diff --git a/src/declarative/items/qsgtextedit_p_p.h b/src/declarative/items/qsgtextedit_p_p.h
new file mode 100644
index 0000000000..63f4bbc341
--- /dev/null
+++ b/src/declarative/items/qsgtextedit_p_p.h
@@ -0,0 +1,143 @@
+// Commit: 27e4302b7f45f22180693d26747f419177c81e27
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTEDIT_P_P_H
+#define QSGTEXTEDIT_P_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 "qsgtextedit_p.h"
+#include "qsgimplicitsizeitem_p_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+
+QT_BEGIN_NAMESPACE
+class QTextLayout;
+class QTextDocument;
+class QTextControl;
+class QSGTextEditPrivate : public QSGImplicitSizePaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGTextEdit)
+
+public:
+ QSGTextEditPrivate()
+ : color("black"), hAlign(QSGTextEdit::AlignLeft), vAlign(QSGTextEdit::AlignTop),
+ imgDirty(true), dirty(false), richText(false), cursorVisible(false), focusOnPress(true),
+ showInputPanelOnFocus(true), clickCausedFocus(false), persistentSelection(true),
+ requireImplicitWidth(false), selectByMouse(false), canPaste(false),
+ hAlignImplicit(true), rightToLeftText(false),
+ textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0), cursorComponent(0), cursor(0),
+ format(QSGTextEdit::AutoText), document(0), wrapMode(QSGTextEdit::NoWrap),
+ mouseSelectionMode(QSGTextEdit::SelectCharacters),
+ yoff(0)
+ {
+#ifdef Q_OS_SYMBIAN
+ if (QSysInfo::symbianVersion() == QSysInfo::SV_SF_1 || QSysInfo::symbianVersion() == QSysInfo::SV_SF_3) {
+ showInputPanelOnFocus = false;
+ }
+#endif
+ }
+
+ void init();
+
+ void updateDefaultTextOption();
+ void relayoutDocument();
+ void updateSelection();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QSGTextEdit::HAlignment, bool forceAlign = false);
+ void mirrorChange();
+ qreal getImplicitWidth() const;
+
+ QString text;
+ QFont font;
+ QFont sourceFont;
+ QColor color;
+ QColor selectionColor;
+ QColor selectedTextColor;
+ QString style;
+ QColor styleColor;
+ QPixmap imgCache;
+ QPixmap imgStyleCache;
+ QSGTextEdit::HAlignment hAlign;
+ QSGTextEdit::VAlignment vAlign;
+
+ bool imgDirty : 1;
+ bool dirty : 1;
+ bool richText : 1;
+ bool cursorVisible : 1;
+ bool focusOnPress : 1;
+ bool showInputPanelOnFocus : 1;
+ bool clickCausedFocus : 1;
+ bool persistentSelection : 1;
+ bool requireImplicitWidth:1;
+ bool selectByMouse:1;
+ bool canPaste:1;
+ bool hAlignImplicit:1;
+ bool rightToLeftText:1;
+
+ qreal textMargin;
+ int lastSelectionStart;
+ int lastSelectionEnd;
+ QDeclarativeComponent* cursorComponent;
+ QSGItem* cursor;
+ QSGTextEdit::TextFormat format;
+ QTextDocument *document;
+ QTextControl *control;
+ QSGTextEdit::WrapMode wrapMode;
+ QSGTextEdit::SelectionMode mouseSelectionMode;
+ int lineCount;
+ int yoff;
+ QSize paintedSize;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXTEDIT_P_P_H
diff --git a/src/declarative/items/qsgtextinput.cpp b/src/declarative/items/qsgtextinput.cpp
new file mode 100644
index 0000000000..9631b3bafb
--- /dev/null
+++ b/src/declarative/items/qsgtextinput.cpp
@@ -0,0 +1,1265 @@
+// Commit: b94176e69efc3948696c6774d5a228fc753b5b29
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtextinput_p.h"
+#include "qsgtextinput_p_p.h"
+#include "qsgcanvas.h"
+
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qwidget_p.h>
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qinputcontext.h>
+#include <QTextBoundaryFinder>
+#include <qstyle.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPrivate *qt_widget_private(QWidget *widget);
+
+QSGTextInput::QSGTextInput(QSGItem* parent)
+: QSGImplicitSizePaintedItem(*(new QSGTextInputPrivate), parent)
+{
+ Q_D(QSGTextInput);
+ d->init();
+}
+
+QSGTextInput::~QSGTextInput()
+{
+}
+
+QString QSGTextInput::text() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->text();
+}
+
+void QSGTextInput::setText(const QString &s)
+{
+ Q_D(QSGTextInput);
+ if(s == text())
+ return;
+ d->control->setText(s);
+}
+
+QFont QSGTextInput::font() const
+{
+ Q_D(const QSGTextInput);
+ return d->sourceFont;
+}
+
+void QSGTextInput::setFont(const QFont &font)
+{
+ Q_D(QSGTextInput);
+ if (d->sourceFont == font)
+ return;
+
+ d->sourceFont = font;
+ QFont oldFont = d->font;
+ d->font = font;
+ if (d->font.pointSizeF() != -1) {
+ // 0.5pt resolution
+ qreal size = qRound(d->font.pointSizeF()*2.0);
+ d->font.setPointSizeF(size/2.0);
+ }
+ if (oldFont != d->font) {
+ d->control->setFont(d->font);
+ if(d->cursorItem){
+ d->cursorItem->setHeight(QFontMetrics(d->font).height());
+ moveCursor();
+ }
+ updateSize();
+ }
+ emit fontChanged(d->sourceFont);
+}
+
+QColor QSGTextInput::color() const
+{
+ Q_D(const QSGTextInput);
+ return d->color;
+}
+
+void QSGTextInput::setColor(const QColor &c)
+{
+ Q_D(QSGTextInput);
+ if (c != d->color) {
+ d->color = c;
+ update();
+ emit colorChanged(c);
+ }
+}
+
+QColor QSGTextInput::selectionColor() const
+{
+ Q_D(const QSGTextInput);
+ return d->selectionColor;
+}
+
+void QSGTextInput::setSelectionColor(const QColor &color)
+{
+ Q_D(QSGTextInput);
+ if (d->selectionColor == color)
+ return;
+
+ d->selectionColor = color;
+ QPalette p = d->control->palette();
+ p.setColor(QPalette::Highlight, d->selectionColor);
+ d->control->setPalette(p);
+ if (d->control->hasSelectedText())
+ update();
+ emit selectionColorChanged(color);
+}
+
+QColor QSGTextInput::selectedTextColor() const
+{
+ Q_D(const QSGTextInput);
+ return d->selectedTextColor;
+}
+
+void QSGTextInput::setSelectedTextColor(const QColor &color)
+{
+ Q_D(QSGTextInput);
+ if (d->selectedTextColor == color)
+ return;
+
+ d->selectedTextColor = color;
+ QPalette p = d->control->palette();
+ p.setColor(QPalette::HighlightedText, d->selectedTextColor);
+ d->control->setPalette(p);
+ if (d->control->hasSelectedText())
+ update();
+ emit selectedTextColorChanged(color);
+}
+
+QSGTextInput::HAlignment QSGTextInput::hAlign() const
+{
+ Q_D(const QSGTextInput);
+ return d->hAlign;
+}
+
+void QSGTextInput::setHAlign(HAlignment align)
+{
+ Q_D(QSGTextInput);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
+ updateRect();
+ d->updateHorizontalScroll();
+ }
+}
+
+void QSGTextInput::resetHAlign()
+{
+ Q_D(QSGTextInput);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete()) {
+ updateRect();
+ d->updateHorizontalScroll();
+ }
+}
+
+QSGTextInput::HAlignment QSGTextInput::effectiveHAlign() const
+{
+ Q_D(const QSGTextInput);
+ QSGTextInput::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QSGTextInput::AlignLeft:
+ effectiveAlignment = QSGTextInput::AlignRight;
+ break;
+ case QSGTextInput::AlignRight:
+ effectiveAlignment = QSGTextInput::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QSGTextInputPrivate::setHAlign(QSGTextInput::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QSGTextInput);
+ if ((hAlign != alignment || forceAlign) && alignment <= QSGTextInput::AlignHCenter) { // justify not supported
+ QSGTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+ emit q->horizontalAlignmentChanged(alignment);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QSGTextInputPrivate::determineHorizontalAlignment()
+{
+ if (hAlignImplicit) {
+ // if no explicit alignment has been set, follow the natural layout direction of the text
+ QString text = control->text();
+ bool isRightToLeft = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
+ return setHAlign(isRightToLeft ? QSGTextInput::AlignRight : QSGTextInput::AlignLeft);
+ }
+ return false;
+}
+
+void QSGTextInputPrivate::mirrorChange()
+{
+ Q_Q(QSGTextInput);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QSGTextInput::AlignRight || hAlign == QSGTextInput::AlignLeft)) {
+ q->updateRect();
+ updateHorizontalScroll();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+bool QSGTextInput::isReadOnly() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->isReadOnly();
+}
+
+void QSGTextInput::setReadOnly(bool ro)
+{
+ Q_D(QSGTextInput);
+ if (d->control->isReadOnly() == ro)
+ return;
+
+ setFlag(QSGItem::ItemAcceptsInputMethod, !ro);
+ d->control->setReadOnly(ro);
+
+ emit readOnlyChanged(ro);
+}
+
+int QSGTextInput::maxLength() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->maxLength();
+}
+
+void QSGTextInput::setMaxLength(int ml)
+{
+ Q_D(QSGTextInput);
+ if (d->control->maxLength() == ml)
+ return;
+
+ d->control->setMaxLength(ml);
+
+ emit maximumLengthChanged(ml);
+}
+
+bool QSGTextInput::isCursorVisible() const
+{
+ Q_D(const QSGTextInput);
+ return d->cursorVisible;
+}
+
+void QSGTextInput::setCursorVisible(bool on)
+{
+ Q_D(QSGTextInput);
+ if (d->cursorVisible == on)
+ return;
+ d->cursorVisible = on;
+ d->control->setCursorBlinkPeriod(on?QApplication::cursorFlashTime():0);
+ QRect r = d->control->cursorRect();
+ if (d->control->inputMask().isEmpty())
+ updateRect(r);
+ else
+ updateRect();
+ emit cursorVisibleChanged(d->cursorVisible);
+}
+
+int QSGTextInput::cursorPosition() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->cursor();
+}
+void QSGTextInput::setCursorPosition(int cp)
+{
+ Q_D(QSGTextInput);
+ if (cp < 0 || cp > d->control->text().length())
+ return;
+ d->control->moveCursor(cp);
+}
+
+QRect QSGTextInput::cursorRectangle() const
+{
+ Q_D(const QSGTextInput);
+ QRect r = d->control->cursorRect();
+ // Scroll and make consistent with TextEdit
+ // QLineControl inexplicably adds 1 to the height and horizontal padding
+ // for unicode direction markers.
+ r.adjust(5 - d->hscroll, 0, -4 - d->hscroll, -1);
+ return r;
+}
+
+int QSGTextInput::selectionStart() const
+{
+ Q_D(const QSGTextInput);
+ return d->lastSelectionStart;
+}
+
+int QSGTextInput::selectionEnd() const
+{
+ Q_D(const QSGTextInput);
+ return d->lastSelectionEnd;
+}
+
+void QSGTextInput::select(int start, int end)
+{
+ Q_D(QSGTextInput);
+ if (start < 0 || end < 0 || start > d->control->text().length() || end > d->control->text().length())
+ return;
+ d->control->setSelection(start, end-start);
+}
+
+QString QSGTextInput::selectedText() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->selectedText();
+}
+
+bool QSGTextInput::focusOnPress() const
+{
+ Q_D(const QSGTextInput);
+ return d->focusOnPress;
+}
+
+void QSGTextInput::setFocusOnPress(bool b)
+{
+ Q_D(QSGTextInput);
+ if (d->focusOnPress == b)
+ return;
+
+ d->focusOnPress = b;
+
+ emit activeFocusOnPressChanged(d->focusOnPress);
+}
+
+bool QSGTextInput::autoScroll() const
+{
+ Q_D(const QSGTextInput);
+ return d->autoScroll;
+}
+
+void QSGTextInput::setAutoScroll(bool b)
+{
+ Q_D(QSGTextInput);
+ if (d->autoScroll == b)
+ return;
+
+ d->autoScroll = b;
+ //We need to repaint so that the scrolling is taking into account.
+ updateSize(true);
+ d->updateHorizontalScroll();
+ emit autoScrollChanged(d->autoScroll);
+}
+
+#ifndef QT_NO_VALIDATOR
+QValidator* QSGTextInput::validator() const
+{
+ Q_D(const QSGTextInput);
+ //###const cast isn't good, but needed for property system?
+ return const_cast<QValidator*>(d->control->validator());
+}
+
+void QSGTextInput::setValidator(QValidator* v)
+{
+ Q_D(QSGTextInput);
+ if (d->control->validator() == v)
+ return;
+
+ d->control->setValidator(v);
+ if(!d->control->hasAcceptableInput()){
+ d->oldValidity = false;
+ emit acceptableInputChanged();
+ }
+
+ emit validatorChanged();
+}
+#endif // QT_NO_VALIDATOR
+
+QString QSGTextInput::inputMask() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->inputMask();
+}
+
+void QSGTextInput::setInputMask(const QString &im)
+{
+ Q_D(QSGTextInput);
+ if (d->control->inputMask() == im)
+ return;
+
+ d->control->setInputMask(im);
+ emit inputMaskChanged(d->control->inputMask());
+}
+
+bool QSGTextInput::hasAcceptableInput() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->hasAcceptableInput();
+}
+
+QSGTextInput::EchoMode QSGTextInput::echoMode() const
+{
+ Q_D(const QSGTextInput);
+ return (QSGTextInput::EchoMode)d->control->echoMode();
+}
+
+void QSGTextInput::setEchoMode(QSGTextInput::EchoMode echo)
+{
+ Q_D(QSGTextInput);
+ if (echoMode() == echo)
+ return;
+ Qt::InputMethodHints imHints = inputMethodHints();
+ if (echo == Password || echo == NoEcho)
+ imHints |= Qt::ImhHiddenText;
+ else
+ imHints &= ~Qt::ImhHiddenText;
+ if (echo != Normal)
+ imHints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ else
+ imHints &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ setInputMethodHints(imHints);
+ d->control->setEchoMode((uint)echo);
+ q_textChanged();
+ emit echoModeChanged(echoMode());
+}
+
+QDeclarativeComponent* QSGTextInput::cursorDelegate() const
+{
+ Q_D(const QSGTextInput);
+ return d->cursorComponent;
+}
+
+void QSGTextInput::setCursorDelegate(QDeclarativeComponent* c)
+{
+ Q_D(QSGTextInput);
+ if (d->cursorComponent == c)
+ return;
+
+ d->cursorComponent = c;
+ if(!c){
+ //note that the components are owned by something else
+ disconnect(d->control, SIGNAL(cursorPositionChanged(int,int)),
+ this, SLOT(moveCursor()));
+ delete d->cursorItem;
+ }else{
+ d->startCreatingCursor();
+ }
+
+ emit cursorDelegateChanged();
+}
+
+void QSGTextInputPrivate::startCreatingCursor()
+{
+ Q_Q(QSGTextInput);
+ q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
+ q, SLOT(moveCursor()));
+ if(cursorComponent->isReady()){
+ q->createCursor();
+ }else if(cursorComponent->isLoading()){
+ q->connect(cursorComponent, SIGNAL(statusChanged(int)),
+ q, SLOT(createCursor()));
+ }else {//isError
+ qmlInfo(q, cursorComponent->errors()) << QSGTextInput::tr("Could not load cursor delegate");
+ }
+}
+
+void QSGTextInput::createCursor()
+{
+ Q_D(QSGTextInput);
+ if(d->cursorComponent->isError()){
+ qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
+ return;
+ }
+
+ if(!d->cursorComponent->isReady())
+ return;
+
+ if(d->cursorItem)
+ delete d->cursorItem;
+ d->cursorItem = qobject_cast<QSGItem*>(d->cursorComponent->create());
+ if(!d->cursorItem){
+ qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
+ return;
+ }
+
+ QDeclarative_setParent_noEvent(d->cursorItem, this);
+ d->cursorItem->setParentItem(this);
+ d->cursorItem->setX(d->control->cursorToX());
+ d->cursorItem->setHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
+}
+
+void QSGTextInput::moveCursor()
+{
+ Q_D(QSGTextInput);
+ if(!d->cursorItem)
+ return;
+ d->updateHorizontalScroll();
+ d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
+}
+
+QRectF QSGTextInput::positionToRectangle(int pos) const
+{
+ Q_D(const QSGTextInput);
+ if (pos > d->control->cursorPosition())
+ pos += d->control->preeditAreaText().length();
+ return QRectF(d->control->cursorToX(pos)-d->hscroll,
+ 0.0,
+ d->control->cursorWidth(),
+ cursorRectangle().height());
+}
+
+int QSGTextInput::positionAt(int x) const
+{
+ return positionAt(x, CursorBetweenCharacters);
+}
+
+int QSGTextInput::positionAt(int x, CursorPosition position) const
+{
+ Q_D(const QSGTextInput);
+ int pos = d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position));
+ const int cursor = d->control->cursor();
+ if (pos > cursor) {
+ const int preeditLength = d->control->preeditAreaText().length();
+ pos = pos > cursor + preeditLength
+ ? pos - preeditLength
+ : cursor;
+ }
+ return pos;
+}
+
+void QSGTextInput::keyPressEvent(QKeyEvent* ev)
+{
+ Q_D(QSGTextInput);
+ // Don't allow MacOSX up/down support, and we don't allow a completer.
+ bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
+ if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
+ // Ignore when moving off the end unless there is a selection,
+ // because then moving will do something (deselect).
+ int cursorPosition = d->control->cursor();
+ if (cursorPosition == 0)
+ ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
+ if (cursorPosition == d->control->text().length())
+ ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
+ }
+ if (ignore) {
+ ev->ignore();
+ } else {
+ d->control->processKeyEvent(ev);
+ }
+ if (!ev->isAccepted())
+ QSGPaintedItem::keyPressEvent(ev);
+}
+
+void QSGTextInput::inputMethodEvent(QInputMethodEvent *ev)
+{
+ Q_D(QSGTextInput);
+ const bool wasComposing = d->control->preeditAreaText().length() > 0;
+ if (d->control->isReadOnly()) {
+ ev->ignore();
+ } else {
+ d->control->processInputMethodEvent(ev);
+ updateSize();
+ d->updateHorizontalScroll();
+ }
+ if (!ev->isAccepted())
+ QSGPaintedItem::inputMethodEvent(ev);
+
+ if (wasComposing != (d->control->preeditAreaText().length() > 0))
+ emit inputMethodComposingChanged();
+}
+
+void QSGTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonDblClick))
+ return;
+ if (d->selectByMouse) {
+ int cursor = d->xToPos(event->pos().x());
+ d->control->selectWordAtPos(cursor);
+ event->setAccepted(true);
+ } else {
+ QSGPaintedItem::mouseDoubleClickEvent(event);
+ }
+}
+
+void QSGTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonPress))
+ return;
+ if(d->focusOnPress){
+ bool hadActiveFocus = hasActiveFocus();
+ forceActiveFocus();
+ if (d->showInputPanelOnFocus) {
+ if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
+ // re-open input panel on press if already focused
+ openSoftwareInputPanel();
+ }
+ } else { // show input panel on click
+ if (hasActiveFocus() && !hadActiveFocus) {
+ d->clickCausedFocus = true;
+ }
+ }
+ }
+ if (d->selectByMouse) {
+ setKeepMouseGrab(false);
+ d->pressPos = event->pos();
+ }
+ bool mark = event->modifiers() & Qt::ShiftModifier;
+ int cursor = d->xToPos(event->pos().x());
+ d->control->moveCursor(cursor, mark);
+ event->setAccepted(true);
+}
+
+void QSGTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseMove))
+ return;
+ if (d->selectByMouse) {
+ if (qAbs(int(event->pos().x() - d->pressPos.x())) > QApplication::startDragDistance())
+ setKeepMouseGrab(true);
+ moveCursorSelection(d->xToPos(event->pos().x()), d->mouseSelectionMode);
+ event->setAccepted(true);
+ } else {
+ QSGPaintedItem::mouseMoveEvent(event);
+ }
+}
+
+void QSGTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonRelease))
+ return;
+ if (d->selectByMouse)
+ setKeepMouseGrab(false);
+ if (!d->showInputPanelOnFocus) { // input panel on click
+ if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ qt_widget_private(canvas())->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
+ }
+ }
+ }
+ d->clickCausedFocus = false;
+ d->control->processEvent(event);
+ if (!event->isAccepted())
+ QSGPaintedItem::mouseReleaseEvent(event);
+}
+
+bool QSGTextInputPrivate::sendMouseEventToInputContext(
+ QGraphicsSceneMouseEvent *event, QEvent::Type eventType)
+{
+#if !defined QT_NO_IM
+ if (event->widget() && control->composeMode()) {
+ int tmp_cursor = xToPos(event->pos().x());
+ int mousePos = tmp_cursor - control->cursor();
+ if (mousePos < 0 || mousePos > control->preeditAreaText().length()) {
+ mousePos = -1;
+ // don't send move events outside the preedit area
+ if (eventType == QEvent::MouseMove)
+ return true;
+ }
+
+ QInputContext *qic = event->widget()->inputContext();
+ if (qic) {
+ QMouseEvent mouseEvent(
+ eventType,
+ event->widget()->mapFromGlobal(event->screenPos()),
+ event->screenPos(),
+ event->button(),
+ event->buttons(),
+ event->modifiers());
+ // may be causing reset() in some input methods
+ qic->mouseHandler(mousePos, &mouseEvent);
+ event->setAccepted(mouseEvent.isAccepted());
+ }
+ if (!control->preeditAreaText().isEmpty())
+ return true;
+ }
+#else
+ Q_UNUSED(event);
+ Q_UNUSED(eventType)
+#endif
+
+ return false;
+}
+
+void QSGTextInput::mouseUngrabEvent()
+{
+ setKeepMouseGrab(false);
+}
+
+bool QSGTextInput::event(QEvent* ev)
+{
+ Q_D(QSGTextInput);
+ //Anything we don't deal with ourselves, pass to the control
+ bool handled = false;
+ switch(ev->type()){
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease://###Should the control be doing anything with release?
+ case QEvent::InputMethod:
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ break;
+ default:
+ handled = d->control->processEvent(ev);
+ }
+ if(!handled)
+ handled = QSGPaintedItem::event(ev);
+ return handled;
+}
+
+void QSGTextInput::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QSGTextInput);
+ if (newGeometry.width() != oldGeometry.width()) {
+ updateSize();
+ d->updateHorizontalScroll();
+ }
+ QSGPaintedItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+int QSGTextInputPrivate::calculateTextWidth()
+{
+ return qRound(control->naturalTextWidth());
+}
+
+void QSGTextInputPrivate::updateHorizontalScroll()
+{
+ Q_Q(QSGTextInput);
+ const int preeditLength = control->preeditAreaText().length();
+ int cix = qRound(control->cursorToX(control->cursor() + preeditLength));
+ QRect br(q->boundingRect().toRect());
+ int widthUsed = calculateTextWidth();
+
+ QSGTextInput::HAlignment effectiveHAlign = q->effectiveHAlign();
+ if (autoScroll) {
+ if (widthUsed <= br.width()) {
+ // text fits in br; use hscroll for alignment
+ switch (effectiveHAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
+ case Qt::AlignRight:
+ hscroll = widthUsed - br.width() - 1;
+ break;
+ case Qt::AlignHCenter:
+ hscroll = (widthUsed - br.width()) / 2;
+ break;
+ default:
+ // Left
+ hscroll = 0;
+ break;
+ }
+ } else if (cix - hscroll >= br.width()) {
+ // text doesn't fit, cursor is to the right of br (scroll right)
+ hscroll = cix - br.width() + 1;
+ } else if (cix - hscroll < 0 && hscroll < widthUsed) {
+ // text doesn't fit, cursor is to the left of br (scroll left)
+ hscroll = cix;
+ } else if (widthUsed - hscroll < br.width()) {
+ // text doesn't fit, text document is to the left of br; align
+ // right
+ hscroll = widthUsed - br.width() + 1;
+ }
+ if (preeditLength > 0) {
+ // check to ensure long pre-edit text doesn't push the cursor
+ // off to the left
+ cix = qRound(control->cursorToX(
+ control->cursor() + qMax(0, control->preeditCursor() - 1)));
+ if (cix < hscroll)
+ hscroll = cix;
+ }
+ } else {
+ switch (effectiveHAlign) {
+ case QSGTextInput::AlignRight:
+ hscroll = q->width() - widthUsed;
+ break;
+ case QSGTextInput::AlignHCenter:
+ hscroll = (q->width() - widthUsed) / 2;
+ break;
+ default:
+ // Left
+ hscroll = 0;
+ break;
+ }
+ }
+}
+
+void QSGTextInput::paint(QPainter *p)
+{
+ // XXX todo
+ QRect r(0, 0, width(), height());
+
+ Q_D(QSGTextInput);
+ p->setRenderHint(QPainter::TextAntialiasing, true);
+ p->save();
+ p->setPen(QPen(d->color));
+ int flags = QLineControl::DrawText;
+ if(!isReadOnly() && d->cursorVisible && !d->cursorItem)
+ flags |= QLineControl::DrawCursor;
+ if (d->control->hasSelectedText())
+ flags |= QLineControl::DrawSelections;
+ QPoint offset = QPoint(0,0);
+ QFontMetrics fm = QFontMetrics(d->font);
+ QRect br(boundingRect().toRect());
+ if (d->autoScroll) {
+ // the y offset is there to keep the baseline constant in case we have script changes in the text.
+ offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
+ } else {
+ offset = QPoint(d->hscroll, 0);
+ }
+ d->control->draw(p, offset, r, flags);
+ p->restore();
+}
+
+QVariant QSGTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QSGTextInput);
+ switch(property) {
+ case Qt::ImMicroFocus:
+ return cursorRectangle();
+ case Qt::ImFont:
+ return font();
+ case Qt::ImCursorPosition:
+ return QVariant(d->control->cursor());
+ case Qt::ImSurroundingText:
+ if (d->control->echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing())
+ return QVariant(displayText());
+ else
+ return QVariant(text());
+ case Qt::ImCurrentSelection:
+ return QVariant(selectedText());
+ case Qt::ImMaximumTextLength:
+ return QVariant(maxLength());
+ case Qt::ImAnchorPosition:
+ if (d->control->selectionStart() == d->control->selectionEnd())
+ return QVariant(d->control->cursor());
+ else if (d->control->selectionStart() == d->control->cursor())
+ return QVariant(d->control->selectionEnd());
+ else
+ return QVariant(d->control->selectionStart());
+ default:
+ return QVariant();
+ }
+}
+
+void QSGTextInput::deselect()
+{
+ Q_D(QSGTextInput);
+ d->control->deselect();
+}
+
+void QSGTextInput::selectAll()
+{
+ Q_D(QSGTextInput);
+ d->control->setSelection(0, d->control->text().length());
+}
+
+bool QSGTextInput::isRightToLeft(int start, int end)
+{
+ Q_D(QSGTextInput);
+ if (start > end) {
+ qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
+ return false;
+ } else {
+ return d->control->text().mid(start, end - start).isRightToLeft();
+ }
+}
+
+#ifndef QT_NO_CLIPBOARD
+void QSGTextInput::cut()
+{
+ Q_D(QSGTextInput);
+ d->control->copy();
+ d->control->del();
+}
+
+void QSGTextInput::copy()
+{
+ Q_D(QSGTextInput);
+ d->control->copy();
+}
+
+void QSGTextInput::paste()
+{
+ Q_D(QSGTextInput);
+ if (!d->control->isReadOnly())
+ d->control->paste();
+}
+#endif // QT_NO_CLIPBOARD
+
+void QSGTextInput::selectWord()
+{
+ Q_D(QSGTextInput);
+ d->control->selectWordAtPos(d->control->cursor());
+}
+
+QString QSGTextInput::passwordCharacter() const
+{
+ Q_D(const QSGTextInput);
+ return QString(d->control->passwordCharacter());
+}
+
+void QSGTextInput::setPasswordCharacter(const QString &str)
+{
+ Q_D(QSGTextInput);
+ if(str.length() < 1)
+ return;
+ d->control->setPasswordCharacter(str.constData()[0]);
+ EchoMode echoMode_ = echoMode();
+ if (echoMode_ == Password || echoMode_ == PasswordEchoOnEdit) {
+ updateSize();
+ }
+ emit passwordCharacterChanged();
+}
+
+QString QSGTextInput::displayText() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->displayText();
+}
+
+bool QSGTextInput::selectByMouse() const
+{
+ Q_D(const QSGTextInput);
+ return d->selectByMouse;
+}
+
+void QSGTextInput::setSelectByMouse(bool on)
+{
+ Q_D(QSGTextInput);
+ if (d->selectByMouse != on) {
+ d->selectByMouse = on;
+ emit selectByMouseChanged(on);
+ }
+}
+
+QSGTextInput::SelectionMode QSGTextInput::mouseSelectionMode() const
+{
+ Q_D(const QSGTextInput);
+ return d->mouseSelectionMode;
+}
+
+void QSGTextInput::setMouseSelectionMode(SelectionMode mode)
+{
+ Q_D(QSGTextInput);
+ if (d->mouseSelectionMode != mode) {
+ d->mouseSelectionMode = mode;
+ emit mouseSelectionModeChanged(mode);
+ }
+}
+
+bool QSGTextInput::canPaste() const
+{
+ Q_D(const QSGTextInput);
+ return d->canPaste;
+}
+
+void QSGTextInput::moveCursorSelection(int position)
+{
+ Q_D(QSGTextInput);
+ d->control->moveCursor(position, true);
+ d->updateHorizontalScroll();
+}
+
+void QSGTextInput::moveCursorSelection(int pos, SelectionMode mode)
+{
+ Q_D(QSGTextInput);
+
+ if (mode == SelectCharacters) {
+ d->control->moveCursor(pos, true);
+ } else if (pos != d->control->cursor()){
+ const int cursor = d->control->cursor();
+ int anchor;
+ if (!d->control->hasSelectedText())
+ anchor = d->control->cursor();
+ else if (d->control->selectionStart() == d->control->cursor())
+ anchor = d->control->selectionEnd();
+ else
+ anchor = d->control->selectionStart();
+
+ if (anchor < pos || (anchor == pos && cursor < pos)) {
+ const QString text = d->control->text();
+ QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
+ finder.setPosition(anchor);
+
+ const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
+ if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
+ || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
+ finder.toPreviousBoundary();
+ }
+ anchor = finder.position() != -1 ? finder.position() : 0;
+
+ finder.setPosition(pos);
+ if (pos > 0 && !finder.boundaryReasons())
+ finder.toNextBoundary();
+ const int cursor = finder.position() != -1 ? finder.position() : text.length();
+
+ d->control->setSelection(anchor, cursor - anchor);
+ } else if (anchor > pos || (anchor == pos && cursor > pos)) {
+ const QString text = d->control->text();
+ QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
+ finder.setPosition(anchor);
+
+ const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
+ if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
+ || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
+ finder.toNextBoundary();
+ }
+
+ anchor = finder.position() != -1 ? finder.position() : text.length();
+
+ finder.setPosition(pos);
+ if (pos < text.length() && !finder.boundaryReasons())
+ finder.toPreviousBoundary();
+ const int cursor = finder.position() != -1 ? finder.position() : 0;
+
+ d->control->setSelection(anchor, cursor - anchor);
+ }
+ }
+}
+
+void QSGTextInput::openSoftwareInputPanel()
+{
+ QEvent event(QEvent::RequestSoftwareInputPanel);
+ if (qApp) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ QEvent event(QEvent::RequestSoftwareInputPanel);
+ QApplication::sendEvent(canvas(), &event);
+ }
+ }
+}
+
+void QSGTextInput::closeSoftwareInputPanel()
+{
+ if (qApp) {
+ if (canvas() && canvas() == qApp->focusWidget()) {
+ QEvent event(QEvent::CloseSoftwareInputPanel);
+ QApplication::sendEvent(canvas(), &event);
+ }
+ }
+}
+
+void QSGTextInput::focusInEvent(QFocusEvent *event)
+{
+ Q_D(const QSGTextInput);
+ if (d->showInputPanelOnFocus) {
+ if (d->focusOnPress && !isReadOnly()) {
+ openSoftwareInputPanel();
+ }
+ }
+ QSGPaintedItem::focusInEvent(event);
+}
+
+void QSGTextInput::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QSGTextInput);
+ if (change == ItemActiveFocusHasChanged) {
+ bool hasFocus = value.boolValue;
+ d->focused = hasFocus;
+ setCursorVisible(hasFocus && d->canvas && d->canvas->hasFocus());
+ if(echoMode() == QSGTextInput::PasswordEchoOnEdit && !hasFocus)
+ d->control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events
+ if (!hasFocus)
+ d->control->deselect();
+ }
+ QSGItem::itemChange(change, value);
+}
+
+bool QSGTextInput::isInputMethodComposing() const
+{
+ Q_D(const QSGTextInput);
+ return d->control->preeditAreaText().length() > 0;
+}
+
+void QSGTextInputPrivate::init()
+{
+ Q_Q(QSGTextInput);
+ control->setCursorWidth(1);
+ control->setPasswordCharacter(QLatin1Char('*'));
+ q->setSmooth(smooth);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QSGItem::ItemAcceptsInputMethod);
+ q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
+ q, SLOT(cursorPosChanged()));
+ q->connect(control, SIGNAL(selectionChanged()),
+ q, SLOT(selectionChanged()));
+ q->connect(control, SIGNAL(textChanged(QString)),
+ q, SLOT(q_textChanged()));
+ q->connect(control, SIGNAL(accepted()),
+ q, SIGNAL(accepted()));
+ q->connect(control, SIGNAL(updateNeeded(QRect)),
+ q, SLOT(updateRect(QRect)));
+#ifndef QT_NO_CLIPBOARD
+ q->connect(q, SIGNAL(readOnlyChanged(bool)),
+ q, SLOT(q_canPasteChanged()));
+ q->connect(QApplication::clipboard(), SIGNAL(dataChanged()),
+ q, SLOT(q_canPasteChanged()));
+ canPaste = !control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
+#endif // QT_NO_CLIPBOARD
+ q->connect(control, SIGNAL(updateMicroFocus()),
+ q, SLOT(updateMicroFocus()));
+ q->connect(control, SIGNAL(displayTextChanged(QString)),
+ q, SLOT(updateRect()));
+ q->updateSize();
+ oldValidity = control->hasAcceptableInput();
+ lastSelectionStart = 0;
+ lastSelectionEnd = 0;
+ QPalette p = control->palette();
+ selectedTextColor = p.color(QPalette::HighlightedText);
+ selectionColor = p.color(QPalette::Highlight);
+ determineHorizontalAlignment();
+}
+
+void QSGTextInput::cursorPosChanged()
+{
+ Q_D(QSGTextInput);
+ d->updateHorizontalScroll();
+ updateRect();//TODO: Only update rect between pos's
+ updateMicroFocus();
+ emit cursorPositionChanged();
+ // XXX todo - not in 4.8?
+#if 0
+ d->control->resetCursorBlinkTimer();
+#endif
+
+ if(!d->control->hasSelectedText()){
+ if(d->lastSelectionStart != d->control->cursor()){
+ d->lastSelectionStart = d->control->cursor();
+ emit selectionStartChanged();
+ }
+ if(d->lastSelectionEnd != d->control->cursor()){
+ d->lastSelectionEnd = d->control->cursor();
+ emit selectionEndChanged();
+ }
+ }
+}
+
+void QSGTextInput::selectionChanged()
+{
+ Q_D(QSGTextInput);
+ updateRect();//TODO: Only update rect in selection
+ emit selectedTextChanged();
+
+ if(d->lastSelectionStart != d->control->selectionStart()){
+ d->lastSelectionStart = d->control->selectionStart();
+ if(d->lastSelectionStart == -1)
+ d->lastSelectionStart = d->control->cursor();
+ emit selectionStartChanged();
+ }
+ if(d->lastSelectionEnd != d->control->selectionEnd()){
+ d->lastSelectionEnd = d->control->selectionEnd();
+ if(d->lastSelectionEnd == -1)
+ d->lastSelectionEnd = d->control->cursor();
+ emit selectionEndChanged();
+ }
+}
+
+void QSGTextInput::q_textChanged()
+{
+ Q_D(QSGTextInput);
+ updateSize();
+ d->determineHorizontalAlignment();
+ d->updateHorizontalScroll();
+ updateMicroFocus();
+ emit textChanged();
+ emit displayTextChanged();
+ if(hasAcceptableInput() != d->oldValidity){
+ d->oldValidity = hasAcceptableInput();
+ emit acceptableInputChanged();
+ }
+}
+
+void QSGTextInput::updateRect(const QRect &r)
+{
+ Q_D(QSGTextInput);
+ if(r == QRect())
+ update();
+ else
+ update(QRect(r.x() - d->hscroll, r.y(), r.width(), r.height()));
+}
+
+QRectF QSGTextInput::boundingRect() const
+{
+ Q_D(const QSGTextInput);
+ QRectF r = QSGPaintedItem::boundingRect();
+
+ int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->control->cursorWidth();
+
+ // Could include font max left/right bearings to either side of rectangle.
+
+ r.setRight(r.right() + cursorWidth);
+ return r;
+}
+
+void QSGTextInput::updateSize(bool needsRedraw)
+{
+ Q_D(QSGTextInput);
+ int w = width();
+ int h = height();
+ setImplicitHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
+ setImplicitWidth(d->calculateTextWidth());
+ setContentsSize(QSize(width(), height()));
+ if(w==width() && h==height() && needsRedraw)
+ update();
+}
+
+void QSGTextInput::q_canPasteChanged()
+{
+ Q_D(QSGTextInput);
+ bool old = d->canPaste;
+#ifndef QT_NO_CLIPBOARD
+ d->canPaste = !d->control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
+#endif
+ if(d->canPaste != old)
+ emit canPasteChanged();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/items/qsgtextinput_p.h b/src/declarative/items/qsgtextinput_p.h
new file mode 100644
index 0000000000..ee04579a54
--- /dev/null
+++ b/src/declarative/items/qsgtextinput_p.h
@@ -0,0 +1,299 @@
+// Commit: 27e4302b7f45f22180693d26747f419177c81e27
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTINPUT_P_H
+#define QSGTEXTINPUT_P_H
+
+#include "qsgimplicitsizeitem_p.h"
+#include <QtGui/qvalidator.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTextInputPrivate;
+class QValidator;
+class Q_AUTOTEST_EXPORT QSGTextInput : public QSGImplicitSizePaintedItem
+{
+ Q_OBJECT
+ Q_ENUMS(HAlignment)
+ Q_ENUMS(EchoMode)
+ Q_ENUMS(SelectionMode)
+
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor NOTIFY selectionColorChanged)
+ Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor NOTIFY selectedTextColorChanged)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
+ Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged)
+
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged)
+ Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible NOTIFY cursorVisibleChanged)
+ Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
+ Q_PROPERTY(QRect cursorRectangle READ cursorRectangle NOTIFY cursorPositionChanged)
+ Q_PROPERTY(QDeclarativeComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged)
+ Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged)
+ Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged)
+ Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged)
+
+ Q_PROPERTY(int maximumLength READ maxLength WRITE setMaxLength NOTIFY maximumLengthChanged)
+#ifndef QT_NO_VALIDATOR
+ Q_PROPERTY(QValidator* validator READ validator WRITE setValidator NOTIFY validatorChanged)
+#endif
+ Q_PROPERTY(QString inputMask READ inputMask WRITE setInputMask NOTIFY inputMaskChanged)
+ Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints)
+
+ Q_PROPERTY(bool acceptableInput READ hasAcceptableInput NOTIFY acceptableInputChanged)
+ Q_PROPERTY(EchoMode echoMode READ echoMode WRITE setEchoMode NOTIFY echoModeChanged)
+ Q_PROPERTY(bool activeFocusOnPress READ focusOnPress WRITE setFocusOnPress NOTIFY activeFocusOnPressChanged)
+ Q_PROPERTY(QString passwordCharacter READ passwordCharacter WRITE setPasswordCharacter NOTIFY passwordCharacterChanged)
+ Q_PROPERTY(QString displayText READ displayText NOTIFY displayTextChanged)
+ Q_PROPERTY(bool autoScroll READ autoScroll WRITE setAutoScroll NOTIFY autoScrollChanged)
+ Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged)
+ Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged)
+ Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged)
+ Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged)
+
+public:
+ QSGTextInput(QSGItem * parent=0);
+ ~QSGTextInput();
+
+ enum EchoMode {//To match QLineEdit::EchoMode
+ Normal,
+ NoEcho,
+ Password,
+ PasswordEchoOnEdit
+ };
+
+ enum HAlignment {
+ AlignLeft = Qt::AlignLeft,
+ AlignRight = Qt::AlignRight,
+ AlignHCenter = Qt::AlignHCenter
+ };
+
+ enum SelectionMode {
+ SelectCharacters,
+ SelectWords
+ };
+
+ enum CursorPosition {
+ CursorBetweenCharacters,
+ CursorOnCharacter
+ };
+
+ //Auxilliary functions needed to control the TextInput from QML
+ Q_INVOKABLE int positionAt(int x) const;
+ Q_INVOKABLE int positionAt(int x, CursorPosition position) const;
+ Q_INVOKABLE QRectF positionToRectangle(int pos) const;
+ Q_INVOKABLE void moveCursorSelection(int pos);
+ Q_INVOKABLE void moveCursorSelection(int pos, SelectionMode mode);
+
+ Q_INVOKABLE void openSoftwareInputPanel();
+ Q_INVOKABLE void closeSoftwareInputPanel();
+
+ QString text() const;
+ void setText(const QString &);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QColor color() const;
+ void setColor(const QColor &c);
+
+ QColor selectionColor() const;
+ void setSelectionColor(const QColor &c);
+
+ QColor selectedTextColor() const;
+ void setSelectedTextColor(const QColor &c);
+
+ HAlignment hAlign() const;
+ void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
+
+ bool isReadOnly() const;
+ void setReadOnly(bool);
+
+ bool isCursorVisible() const;
+ void setCursorVisible(bool on);
+
+ int cursorPosition() const;
+ void setCursorPosition(int cp);
+
+ QRect cursorRectangle() const;
+
+ int selectionStart() const;
+ int selectionEnd() const;
+
+ QString selectedText() const;
+
+ int maxLength() const;
+ void setMaxLength(int ml);
+
+#ifndef QT_NO_VALIDATOR
+ QValidator * validator() const;
+ void setValidator(QValidator* v);
+#endif
+ QString inputMask() const;
+ void setInputMask(const QString &im);
+
+ EchoMode echoMode() const;
+ void setEchoMode(EchoMode echo);
+
+ QString passwordCharacter() const;
+ void setPasswordCharacter(const QString &str);
+
+ QString displayText() const;
+
+ QDeclarativeComponent* cursorDelegate() const;
+ void setCursorDelegate(QDeclarativeComponent*);
+
+ bool focusOnPress() const;
+ void setFocusOnPress(bool);
+
+ bool autoScroll() const;
+ void setAutoScroll(bool);
+
+ bool selectByMouse() const;
+ void setSelectByMouse(bool);
+
+ SelectionMode mouseSelectionMode() const;
+ void setMouseSelectionMode(SelectionMode mode);
+
+ bool hasAcceptableInput() const;
+
+ void paint(QPainter *p);
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+
+ QRectF boundingRect() const;
+ bool canPaste() const;
+
+ bool isInputMethodComposing() const;
+
+Q_SIGNALS:
+ void textChanged();
+ void cursorPositionChanged();
+ void selectionStartChanged();
+ void selectionEndChanged();
+ void selectedTextChanged();
+ void accepted();
+ void acceptableInputChanged();
+ void colorChanged(const QColor &color);
+ void selectionColorChanged(const QColor &color);
+ void selectedTextColorChanged(const QColor &color);
+ void fontChanged(const QFont &font);
+ void horizontalAlignmentChanged(HAlignment alignment);
+ void readOnlyChanged(bool isReadOnly);
+ void cursorVisibleChanged(bool isCursorVisible);
+ void cursorDelegateChanged();
+ void maximumLengthChanged(int maximumLength);
+ void validatorChanged();
+ void inputMaskChanged(const QString &inputMask);
+ void echoModeChanged(EchoMode echoMode);
+ void passwordCharacterChanged();
+ void displayTextChanged();
+ void activeFocusOnPressChanged(bool activeFocusOnPress);
+ void autoScrollChanged(bool autoScroll);
+ void selectByMouseChanged(bool selectByMouse);
+ void mouseSelectionModeChanged(SelectionMode mode);
+ void canPasteChanged();
+ void inputMethodComposingChanged();
+ void effectiveHorizontalAlignmentChanged();
+
+protected:
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ bool sceneEvent(QEvent *event);
+ void keyPressEvent(QKeyEvent* ev);
+ void inputMethodEvent(QInputMethodEvent *);
+ void mouseUngrabEvent();
+ bool event(QEvent *e);
+ void focusInEvent(QFocusEvent *event);
+ virtual void itemChange(ItemChange, const ItemChangeData &);
+
+public Q_SLOTS:
+ void selectAll();
+ void selectWord();
+ void select(int start, int end);
+ void deselect();
+ bool isRightToLeft(int start, int end);
+#ifndef QT_NO_CLIPBOARD
+ void cut();
+ void copy();
+ void paste();
+#endif
+
+private Q_SLOTS:
+ void updateSize(bool needsRedraw = true);
+ void q_textChanged();
+ void selectionChanged();
+ void createCursor();
+ void moveCursor();
+ void cursorPosChanged();
+ void updateRect(const QRect &r = QRect());
+ void q_canPasteChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QSGTextInput)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGTextInput)
+#ifndef QT_NO_VALIDATOR
+QML_DECLARE_TYPE(QValidator)
+QML_DECLARE_TYPE(QIntValidator)
+QML_DECLARE_TYPE(QDoubleValidator)
+QML_DECLARE_TYPE(QRegExpValidator)
+#endif
+
+QT_END_HEADER
+
+#endif // QSGTEXTINPUT_P_H
diff --git a/src/declarative/items/qsgtextinput_p_p.h b/src/declarative/items/qsgtextinput_p_p.h
new file mode 100644
index 0000000000..00db1e995c
--- /dev/null
+++ b/src/declarative/items/qsgtextinput_p_p.h
@@ -0,0 +1,150 @@
+// Commit: 27e4302b7f45f22180693d26747f419177c81e27
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTINPUT_P_P_H
+#define QSGTEXTINPUT_P_P_H
+
+#include "qsgtextinput_p.h"
+#include "qsgtext_p.h"
+#include "qsgimplicitsizeitem_p_p.h"
+
+#include <private/qlinecontrol_p.h>
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtCore/qpointer.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 Q_AUTOTEST_EXPORT QSGTextInputPrivate : public QSGImplicitSizePaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGTextInput)
+public:
+ QSGTextInputPrivate() : control(new QLineControl(QString())),
+ color((QRgb)0), style(QSGText::Normal),
+ styleColor((QRgb)0), hAlign(QSGTextInput::AlignLeft),
+ mouseSelectionMode(QSGTextInput::SelectCharacters),
+ hscroll(0), oldScroll(0), oldValidity(false), focused(false), focusOnPress(true),
+ showInputPanelOnFocus(true), clickCausedFocus(false), cursorVisible(false),
+ autoScroll(true), selectByMouse(false), canPaste(false), hAlignImplicit(true)
+ {
+#ifdef Q_OS_SYMBIAN
+ if (QSysInfo::symbianVersion() == QSysInfo::SV_SF_1 || QSysInfo::symbianVersion() == QSysInfo::SV_SF_3) {
+ showInputPanelOnFocus = false;
+ }
+#endif
+
+ }
+
+ ~QSGTextInputPrivate()
+ {
+ delete control;
+ }
+
+ int xToPos(int x, QTextLine::CursorPosition betweenOrOn = QTextLine::CursorBetweenCharacters) const
+ {
+ Q_Q(const QSGTextInput);
+ QRect cr = q->boundingRect().toRect();
+ x-= cr.x() - hscroll;
+ return control->xToPos(x, betweenOrOn);
+ }
+
+ void init();
+ void startCreatingCursor();
+ void updateHorizontalScroll();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QSGTextInput::HAlignment, bool forceAlign = false);
+ void mirrorChange();
+ int calculateTextWidth();
+ bool sendMouseEventToInputContext(QGraphicsSceneMouseEvent *event, QEvent::Type eventType);
+
+ QLineControl* control;
+
+ QFont font;
+ QFont sourceFont;
+ QColor color;
+ QColor selectionColor;
+ QColor selectedTextColor;
+ QSGText::TextStyle style;
+ QColor styleColor;
+ QSGTextInput::HAlignment hAlign;
+ QSGTextInput::SelectionMode mouseSelectionMode;
+ QPointer<QDeclarativeComponent> cursorComponent;
+ QPointer<QSGItem> cursorItem;
+ QPointF pressPos;
+
+ int lastSelectionStart;
+ int lastSelectionEnd;
+ int oldHeight;
+ int oldWidth;
+ int hscroll;
+ int oldScroll;
+
+ bool oldValidity:1;
+ bool focused:1;
+ bool focusOnPress:1;
+ bool showInputPanelOnFocus:1;
+ bool clickCausedFocus:1;
+ bool cursorVisible:1;
+ bool autoScroll:1;
+ bool selectByMouse:1;
+ bool canPaste:1;
+ bool hAlignImplicit:1;
+
+ static inline QSGTextInputPrivate *get(QSGTextInput *t) {
+ return t->d_func();
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXTINPUT_P_P_H
diff --git a/src/declarative/items/qsgtextnode.cpp b/src/declarative/items/qsgtextnode.cpp
new file mode 100644
index 0000000000..3bbe0d2832
--- /dev/null
+++ b/src/declarative/items/qsgtextnode.cpp
@@ -0,0 +1,457 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtextnode_p.h"
+#include "qsgsimplerectnode.h"
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgdistancefieldglyphcache_p.h>
+#include <private/qsgdistancefieldglyphnode_p.h>
+
+#include <private/qsgcontext_p.h>
+
+#include <qmath.h>
+#include <qtextdocument.h>
+#include <qtextlayout.h>
+#include <qabstracttextdocumentlayout.h>
+#include <qxmlstream.h>
+#include <qrawfont.h>
+#include <private/qdeclarativestyledtext_p.h>
+#include <private/qfont_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qrawfont_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Creates an empty QSGTextNode
+*/
+QSGTextNode::QSGTextNode(QSGContext *context)
+: m_context(context)
+{
+#if defined(QML_RUNTIME_TESTING)
+ description = QLatin1String("text");
+#endif
+}
+
+QSGTextNode::~QSGTextNode()
+{
+}
+
+#if 0
+void QSGTextNode::setColor(const QColor &color)
+{
+ if (m_usePixmapCache) {
+ setUpdateFlag(UpdateNodes);
+ } else {
+ for (int i=0; i<childCount(); ++i) {
+ QSGNode *childNode = childAtIndex(i);
+ if (childNode->subType() == GlyphNodeSubType) {
+ QSGGlyphNode *glyphNode = static_cast<QSGGlyphNode *>(childNode);
+ if (glyphNode->color() == m_color)
+ glyphNode->setColor(color);
+ } else if (childNode->subType() == SolidRectNodeSubType) {
+ QSGSimpleRectNode *solidRectNode = static_cast<QSGSimpleRectNode *>(childNode);
+ if (solidRectNode->color() == m_color)
+ solidRectNode->setColor(color);
+ }
+ }
+ }
+ m_color = color;
+}
+
+void QSGTextNode::setStyleColor(const QColor &styleColor)
+{
+ if (m_textStyle != QSGTextNode::NormalTextStyle) {
+ if (m_usePixmapCache) {
+ setUpdateFlag(UpdateNodes);
+ } else {
+ for (int i=0; i<childCount(); ++i) {
+ QSGNode *childNode = childAtIndex(i);
+ if (childNode->subType() == GlyphNodeSubType) {
+ QSGGlyphNode *glyphNode = static_cast<QSGGlyphNode *>(childNode);
+ if (glyphNode->color() == m_styleColor)
+ glyphNode->setColor(styleColor);
+ } else if (childNode->subType() == SolidRectNodeSubType) {
+ QSGSimpleRectNode *solidRectNode = static_cast<QSGSimpleRectNode *>(childNode);
+ if (solidRectNode->color() == m_styleColor)
+ solidRectNode->setColor(styleColor);
+ }
+ }
+ }
+ }
+ m_styleColor = styleColor;
+}
+#endif
+
+void QSGTextNode::addTextDecorations(const QPointF &position, const QRawFont &font, const QColor &color,
+ qreal width, bool hasOverline, bool hasStrikeOut, bool hasUnderline)
+{
+ Q_ASSERT(font.isValid());
+ QRawFontPrivate *dptrFont = QRawFontPrivate::get(font);
+ QFontEngine *fontEngine = dptrFont->fontEngine;
+
+ qreal lineThickness = fontEngine->lineThickness().toReal();
+
+ QRectF line(position.x(), position.y() - lineThickness / 2.0, width, lineThickness);
+
+ if (hasUnderline) {
+ int underlinePosition = fontEngine->underlinePosition().ceil().toInt();
+ QRectF underline(line);
+ underline.translate(0.0, underlinePosition);
+ appendChildNode(new QSGSimpleRectNode(underline, color));
+ }
+
+ qreal ascent = font.ascent();
+ if (hasOverline) {
+ QRectF overline(line);
+ overline.translate(0.0, -ascent);
+ appendChildNode(new QSGSimpleRectNode(overline, color));
+ }
+
+ if (hasStrikeOut) {
+ QRectF strikeOut(line);
+ strikeOut.translate(0.0, ascent / -3.0);
+ appendChildNode(new QSGSimpleRectNode(strikeOut, color));
+ }
+}
+
+QSGGlyphNode *QSGTextNode::addGlyphs(const QPointF &position, const QGlyphs &glyphs, const QColor &color,
+ QSGText::TextStyle style, const QColor &styleColor)
+{
+ QSGGlyphNode *node = m_context->createGlyphNode();
+ if (QSGDistanceFieldGlyphCache::distanceFieldEnabled()) {
+ QSGDistanceFieldGlyphNode *dfNode = static_cast<QSGDistanceFieldGlyphNode *>(node);
+ dfNode->setStyle(style);
+ dfNode->setStyleColor(styleColor);
+ }
+ node->setGlyphs(position, glyphs);
+ node->setColor(color);
+
+ appendChildNode(node);
+
+ return node;
+}
+
+void QSGTextNode::addTextDocument(const QPointF &position, QTextDocument *textDocument, const QColor &color,
+ QSGText::TextStyle style, const QColor &styleColor)
+{
+ Q_UNUSED(position)
+ QTextFrame *textFrame = textDocument->rootFrame();
+ QPointF p = textDocument->documentLayout()->frameBoundingRect(textFrame).topLeft();
+
+ QTextFrame::iterator it = textFrame->begin();
+ while (!it.atEnd()) {
+ addTextBlock(p, textDocument, it.currentBlock(), color, style, styleColor);
+ ++it;
+ }
+}
+
+void QSGTextNode::addTextLayout(const QPointF &position, QTextLayout *textLayout, const QColor &color,
+ QSGText::TextStyle style, const QColor &styleColor)
+{
+ QList<QGlyphs> glyphsList(textLayout->glyphs());
+ for (int i=0; i<glyphsList.size(); ++i)
+ addGlyphs(position, glyphsList.at(i), color, style, styleColor);
+
+ QFont font = textLayout->font();
+ QRawFont rawFont = QRawFont::fromFont(font);
+ if (font.strikeOut() || font.underline() || font.overline()) {
+ addTextDecorations(position, rawFont, color, textLayout->boundingRect().width(),
+ font.overline(), font.strikeOut(), font.underline());
+ }
+}
+
+
+/*!
+ Returns true if \a text contains any HTML tags, attributes or CSS properties which are unrelated
+ to text, fonts or text layout. Otherwise the function returns false. If the return value is
+ false, \a text is considered to be easily representable in the scenegraph. If it returns true,
+ then the text should be prerendered into a pixmap before it's displayed on screen.
+*/
+bool QSGTextNode::isComplexRichText(QTextDocument *doc)
+{
+ if (doc == 0)
+ return false;
+
+ static QSet<QString> supportedTags;
+ if (supportedTags.isEmpty()) {
+ supportedTags.insert(QLatin1String("i"));
+ supportedTags.insert(QLatin1String("b"));
+ supportedTags.insert(QLatin1String("u"));
+ supportedTags.insert(QLatin1String("div"));
+ supportedTags.insert(QLatin1String("big"));
+ supportedTags.insert(QLatin1String("blockquote"));
+ supportedTags.insert(QLatin1String("body"));
+ supportedTags.insert(QLatin1String("br"));
+ supportedTags.insert(QLatin1String("center"));
+ supportedTags.insert(QLatin1String("cite"));
+ supportedTags.insert(QLatin1String("code"));
+ supportedTags.insert(QLatin1String("tt"));
+ supportedTags.insert(QLatin1String("dd"));
+ supportedTags.insert(QLatin1String("dfn"));
+ supportedTags.insert(QLatin1String("em"));
+ supportedTags.insert(QLatin1String("font"));
+ supportedTags.insert(QLatin1String("h1"));
+ supportedTags.insert(QLatin1String("h2"));
+ supportedTags.insert(QLatin1String("h3"));
+ supportedTags.insert(QLatin1String("h4"));
+ supportedTags.insert(QLatin1String("h5"));
+ supportedTags.insert(QLatin1String("h6"));
+ supportedTags.insert(QLatin1String("head"));
+ supportedTags.insert(QLatin1String("html"));
+ supportedTags.insert(QLatin1String("meta"));
+ supportedTags.insert(QLatin1String("nobr"));
+ supportedTags.insert(QLatin1String("p"));
+ supportedTags.insert(QLatin1String("pre"));
+ supportedTags.insert(QLatin1String("qt"));
+ supportedTags.insert(QLatin1String("s"));
+ supportedTags.insert(QLatin1String("samp"));
+ supportedTags.insert(QLatin1String("small"));
+ supportedTags.insert(QLatin1String("span"));
+ supportedTags.insert(QLatin1String("strong"));
+ supportedTags.insert(QLatin1String("sub"));
+ supportedTags.insert(QLatin1String("sup"));
+ supportedTags.insert(QLatin1String("title"));
+ supportedTags.insert(QLatin1String("var"));
+ supportedTags.insert(QLatin1String("style"));
+ }
+
+ static QSet<QCss::Property> supportedCssProperties;
+ if (supportedCssProperties.isEmpty()) {
+ supportedCssProperties.insert(QCss::Color);
+ supportedCssProperties.insert(QCss::Float);
+ supportedCssProperties.insert(QCss::Font);
+ supportedCssProperties.insert(QCss::FontFamily);
+ supportedCssProperties.insert(QCss::FontSize);
+ supportedCssProperties.insert(QCss::FontStyle);
+ supportedCssProperties.insert(QCss::FontWeight);
+ supportedCssProperties.insert(QCss::Margin);
+ supportedCssProperties.insert(QCss::MarginBottom);
+ supportedCssProperties.insert(QCss::MarginLeft);
+ supportedCssProperties.insert(QCss::MarginRight);
+ supportedCssProperties.insert(QCss::MarginTop);
+ supportedCssProperties.insert(QCss::TextDecoration);
+ supportedCssProperties.insert(QCss::TextIndent);
+ supportedCssProperties.insert(QCss::TextUnderlineStyle);
+ supportedCssProperties.insert(QCss::VerticalAlignment);
+ supportedCssProperties.insert(QCss::Whitespace);
+ supportedCssProperties.insert(QCss::Padding);
+ supportedCssProperties.insert(QCss::PaddingLeft);
+ supportedCssProperties.insert(QCss::PaddingRight);
+ supportedCssProperties.insert(QCss::PaddingTop);
+ supportedCssProperties.insert(QCss::PaddingBottom);
+ supportedCssProperties.insert(QCss::PageBreakBefore);
+ supportedCssProperties.insert(QCss::PageBreakAfter);
+ supportedCssProperties.insert(QCss::Width);
+ supportedCssProperties.insert(QCss::Height);
+ supportedCssProperties.insert(QCss::MinimumWidth);
+ supportedCssProperties.insert(QCss::MinimumHeight);
+ supportedCssProperties.insert(QCss::MaximumWidth);
+ supportedCssProperties.insert(QCss::MaximumHeight);
+ supportedCssProperties.insert(QCss::Left);
+ supportedCssProperties.insert(QCss::Right);
+ supportedCssProperties.insert(QCss::Top);
+ supportedCssProperties.insert(QCss::Bottom);
+ supportedCssProperties.insert(QCss::Position);
+ supportedCssProperties.insert(QCss::TextAlignment);
+ supportedCssProperties.insert(QCss::FontVariant);
+ }
+
+ QXmlStreamReader reader(doc->toHtml("utf-8"));
+ while (!reader.atEnd()) {
+ reader.readNext();
+
+ if (reader.isStartElement()) {
+ if (!supportedTags.contains(reader.name().toString().toLower()))
+ return true;
+
+ QXmlStreamAttributes attributes = reader.attributes();
+ if (attributes.hasAttribute(QLatin1String("bgcolor")))
+ return true;
+ if (attributes.hasAttribute(QLatin1String("style"))) {
+ QCss::StyleSheet styleSheet;
+ QCss::Parser(attributes.value(QLatin1String("style")).toString()).parse(&styleSheet);
+
+ QVector<QCss::Declaration> decls;
+ for (int i=0; i<styleSheet.pageRules.size(); ++i)
+ decls += styleSheet.pageRules.at(i).declarations;
+
+ QVector<QCss::StyleRule> styleRules =
+ styleSheet.styleRules
+ + styleSheet.idIndex.values().toVector()
+ + styleSheet.nameIndex.values().toVector();
+ for (int i=0; i<styleSheet.mediaRules.size(); ++i)
+ styleRules += styleSheet.mediaRules.at(i).styleRules;
+
+ for (int i=0; i<styleRules.size(); ++i)
+ decls += styleRules.at(i).declarations;
+
+ for (int i=0; i<decls.size(); ++i) {
+ if (!supportedCssProperties.contains(decls.at(i).d->propertyId))
+ return true;
+ }
+
+ }
+ }
+ }
+
+ return reader.hasError();
+}
+
+void QSGTextNode::addTextBlock(const QPointF &position, QTextDocument *textDocument, const QTextBlock &block,
+ const QColor &overrideColor, QSGText::TextStyle style, const QColor &styleColor)
+{
+ if (!block.isValid())
+ return;
+
+ QPointF blockPosition = textDocument->documentLayout()->blockBoundingRect(block).topLeft();
+
+ QTextBlock::iterator it = block.begin();
+ while (!it.atEnd()) {
+ QTextFragment fragment = it.fragment();
+ if (!fragment.text().isEmpty()) {
+ QTextCharFormat charFormat = fragment.charFormat();
+ QColor color = overrideColor.isValid()
+ ? overrideColor
+ : charFormat.foreground().color();
+
+ QFontMetricsF fm(fragment.charFormat().font());
+ QPointF ascent(0, fm.ascent());
+
+ QList<QGlyphs> glyphsList = fragment.glyphs();
+ for (int i=0; i<glyphsList.size(); ++i) {
+ QGlyphs glyphs = glyphsList.at(i);
+ QSGGlyphNode *glyphNode = addGlyphs(position + blockPosition + ascent, glyphs,
+ color, style, styleColor);
+
+ QRawFont font = glyphs.font();
+ QPointF baseLine = glyphNode->baseLine();
+ qreal width = glyphNode->boundingRect().width();
+ addTextDecorations(baseLine, font, color, width,
+ glyphs.overline(), glyphs.strikeOut(), glyphs.underline());
+ }
+ }
+
+ ++it;
+ }
+}
+
+void QSGTextNode::deleteContent()
+{
+ while (childCount() > 0)
+ delete childAtIndex(0);
+}
+
+#if 0
+void QSGTextNode::updateNodes()
+{
+ return;
+ deleteContent();
+ if (m_text.isEmpty())
+ return;
+
+ if (m_usePixmapCache) {
+ // ### gunnar: port properly
+// QPixmap pixmap = generatedPixmap();
+// if (pixmap.isNull())
+// return;
+
+// QSGImageNode *pixmapNode = m_context->createImageNode();
+// pixmapNode->setRect(pixmap.rect());
+// pixmapNode->setSourceRect(pixmap.rect());
+// pixmapNode->setOpacity(m_opacity);
+// pixmapNode->setClampToEdge(true);
+// pixmapNode->setLinearFiltering(m_linearFiltering);
+
+// appendChildNode(pixmapNode);
+ } else {
+ if (m_text.isEmpty())
+ return;
+
+ // Implement styling by drawing text several times at slight shifts. shiftForStyle
+ // contains the sequence of shifted positions at which to draw the text. All except
+ // the last will be drawn with styleColor.
+ QList<QPointF> shiftForStyle;
+ switch (m_textStyle) {
+ case OutlineTextStyle:
+ // ### Should be made faster by implementing outline material
+ shiftForStyle << QPointF(-1, 0);
+ shiftForStyle << QPointF(0, -1);
+ shiftForStyle << QPointF(1, 0);
+ shiftForStyle << QPointF(0, 1);
+ break;
+ case SunkenTextStyle:
+ shiftForStyle << QPointF(0, -1);
+ break;
+ case RaisedTextStyle:
+ shiftForStyle << QPointF(0, 1);
+ break;
+ default:
+ break;
+ }
+
+ shiftForStyle << QPointF(0, 0); // Regular position
+ while (!shiftForStyle.isEmpty()) {
+ QPointF shift = shiftForStyle.takeFirst();
+
+ // Use styleColor for all but last shift
+ if (m_richText) {
+ QColor overrideColor = shiftForStyle.isEmpty() ? QColor() : m_styleColor;
+
+ QTextFrame *textFrame = m_textDocument->rootFrame();
+ QPointF p = m_textDocument->documentLayout()->frameBoundingRect(textFrame).topLeft();
+
+ QTextFrame::iterator it = textFrame->begin();
+ while (!it.atEnd()) {
+ addTextBlock(shift + p, it.currentBlock(), overrideColor);
+ ++it;
+ }
+ } else {
+ addTextLayout(shift, m_textLayout, shiftForStyle.isEmpty()
+ ? m_color
+ : m_styleColor);
+ }
+ }
+ }
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgtextnode_p.h b/src/declarative/items/qsgtextnode_p.h
new file mode 100644
index 0000000000..e7bd95faee
--- /dev/null
+++ b/src/declarative/items/qsgtextnode_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTNODE_P_H
+#define QSGTEXTNODE_P_H
+
+#include <qsgnode.h>
+#include <qsgtext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTextLayout;
+class QSGGlyphNode;
+class QTextBlock;
+class QColor;
+class QTextDocument;
+class QSGContext;
+class QRawFont;
+
+class QSGTextNode : public QSGTransformNode
+{
+public:
+ QSGTextNode(QSGContext *);
+ ~QSGTextNode();
+
+ static bool isComplexRichText(QTextDocument *);
+
+ void deleteContent();
+ void addTextLayout(const QPointF &position, QTextLayout *textLayout, const QColor &color = QColor(),
+ QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor());
+ void addTextDocument(const QPointF &position, QTextDocument *textDocument, const QColor &color = QColor(),
+ QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor());
+
+private:
+ void addTextBlock(const QPointF &position, QTextDocument *textDocument, const QTextBlock &block,
+ const QColor &overrideColor, QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor());
+ QSGGlyphNode *addGlyphs(const QPointF &position, const QGlyphs &glyphs, const QColor &color,
+ QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor());
+ void addTextDecorations(const QPointF &position, const QRawFont &font, const QColor &color,
+ qreal width, bool hasOverline, bool hasStrikeOut, bool hasUnderline);
+ QSGContext *m_context;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXTNODE_P_H
diff --git a/src/declarative/items/qsgtranslate.cpp b/src/declarative/items/qsgtranslate.cpp
new file mode 100644
index 0000000000..5f7112bd42
--- /dev/null
+++ b/src/declarative/items/qsgtranslate.cpp
@@ -0,0 +1,297 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtranslate_p.h"
+#include "qsgitem_p.h"
+
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGTranslatePrivate : public QSGTransformPrivate
+{
+public:
+ QSGTranslatePrivate()
+ : x(0), y(0) {}
+
+ qreal x;
+ qreal y;
+};
+
+QSGTranslate::QSGTranslate(QObject *parent)
+: QSGTransform(*new QSGTranslatePrivate, parent)
+{
+}
+
+QSGTranslate::~QSGTranslate()
+{
+}
+
+qreal QSGTranslate::x() const
+{
+ Q_D(const QSGTranslate);
+ return d->x;
+}
+
+void QSGTranslate::setX(qreal x)
+{
+ Q_D(QSGTranslate);
+ if (d->x == x)
+ return;
+ d->x = x;
+ update();
+ emit xChanged();
+}
+
+qreal QSGTranslate::y() const
+{
+ Q_D(const QSGTranslate);
+ return d->y;
+}
+void QSGTranslate::setY(qreal y)
+{
+ Q_D(QSGTranslate);
+ if (d->y == y)
+ return;
+ d->y = y;
+ update();
+ emit yChanged();
+}
+
+void QSGTranslate::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QSGTranslate);
+ matrix->translate(d->x, d->y, 0);
+}
+
+class QSGScalePrivate : public QSGTransformPrivate
+{
+public:
+ QSGScalePrivate()
+ : xScale(1), yScale(1), zScale(1) {}
+ QVector3D origin;
+ qreal xScale;
+ qreal yScale;
+ qreal zScale;
+};
+
+QSGScale::QSGScale(QObject *parent)
+ : QSGTransform(*new QSGScalePrivate, parent)
+{
+}
+
+QSGScale::~QSGScale()
+{
+}
+
+QVector3D QSGScale::origin() const
+{
+ Q_D(const QSGScale);
+ return d->origin;
+}
+void QSGScale::setOrigin(const QVector3D &point)
+{
+ Q_D(QSGScale);
+ if (d->origin == point)
+ return;
+ d->origin = point;
+ update();
+ emit originChanged();
+}
+
+qreal QSGScale::xScale() const
+{
+ Q_D(const QSGScale);
+ return d->xScale;
+}
+void QSGScale::setXScale(qreal scale)
+{
+ Q_D(QSGScale);
+ if (d->xScale == scale)
+ return;
+ d->xScale = scale;
+ update();
+ emit xScaleChanged();
+ emit scaleChanged();
+}
+
+qreal QSGScale::yScale() const
+{
+ Q_D(const QSGScale);
+ return d->yScale;
+}
+void QSGScale::setYScale(qreal scale)
+{
+ Q_D(QSGScale);
+ if (d->yScale == scale)
+ return;
+ d->yScale = scale;
+ update();
+ emit yScaleChanged();
+ emit scaleChanged();
+}
+
+qreal QSGScale::zScale() const
+{
+ Q_D(const QSGScale);
+ return d->zScale;
+}
+void QSGScale::setZScale(qreal scale)
+{
+ Q_D(QSGScale);
+ if (d->zScale == scale)
+ return;
+ d->zScale = scale;
+ update();
+ emit zScaleChanged();
+ emit scaleChanged();
+}
+
+void QSGScale::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QSGScale);
+ matrix->translate(d->origin);
+ matrix->scale(d->xScale, d->yScale, d->zScale);
+ matrix->translate(-d->origin);
+}
+
+class QSGRotationPrivate : public QSGTransformPrivate
+{
+public:
+ QSGRotationPrivate()
+ : angle(0), axis(0, 0, 1) {}
+ QVector3D origin;
+ qreal angle;
+ QVector3D axis;
+};
+
+QSGRotation::QSGRotation(QObject *parent)
+ : QSGTransform(*new QSGRotationPrivate, parent)
+{
+}
+
+QSGRotation::~QSGRotation()
+{
+}
+
+QVector3D QSGRotation::origin() const
+{
+ Q_D(const QSGRotation);
+ return d->origin;
+}
+
+void QSGRotation::setOrigin(const QVector3D &point)
+{
+ Q_D(QSGRotation);
+ if (d->origin == point)
+ return;
+ d->origin = point;
+ update();
+ emit originChanged();
+}
+
+qreal QSGRotation::angle() const
+{
+ Q_D(const QSGRotation);
+ return d->angle;
+}
+void QSGRotation::setAngle(qreal angle)
+{
+ Q_D(QSGRotation);
+ if (d->angle == angle)
+ return;
+ d->angle = angle;
+ update();
+ emit angleChanged();
+}
+
+QVector3D QSGRotation::axis() const
+{
+ Q_D(const QSGRotation);
+ return d->axis;
+}
+void QSGRotation::setAxis(const QVector3D &axis)
+{
+ Q_D(QSGRotation);
+ if (d->axis == axis)
+ return;
+ d->axis = axis;
+ update();
+ emit axisChanged();
+}
+
+void QSGRotation::setAxis(Qt::Axis axis)
+{
+ switch (axis)
+ {
+ case Qt::XAxis:
+ setAxis(QVector3D(1, 0, 0));
+ break;
+ case Qt::YAxis:
+ setAxis(QVector3D(0, 1, 0));
+ break;
+ case Qt::ZAxis:
+ setAxis(QVector3D(0, 0, 1));
+ break;
+ }
+}
+
+struct QGraphicsRotation {
+ static inline void projectedRotate(QMatrix4x4 *matrix, qreal angle, qreal x, qreal y, qreal z)
+ {
+ matrix->projectedRotate(angle, x, y, z);
+ }
+};
+
+void QSGRotation::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QSGRotation);
+
+ if (d->angle == 0. || d->axis.isNull())
+ return;
+
+ matrix->translate(d->origin);
+ QGraphicsRotation::projectedRotate(matrix, d->angle, d->axis.x(), d->axis.y(), d->axis.z());
+ matrix->translate(-d->origin);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgtranslate_p.h b/src/declarative/items/qsgtranslate_p.h
new file mode 100644
index 0000000000..de05778b1e
--- /dev/null
+++ b/src/declarative/items/qsgtranslate_p.h
@@ -0,0 +1,162 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTRANSLATE_P_H
+#define QSGTRANSLATE_P_H
+
+#include "qsgitem.h"
+
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTranslatePrivate;
+class Q_AUTOTEST_EXPORT QSGTranslate : public QSGTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+
+public:
+ QSGTranslate(QObject *parent = 0);
+ ~QSGTranslate();
+
+ qreal x() const;
+ void setX(qreal);
+
+ qreal y() const;
+ void setY(qreal);
+
+ void applyTo(QMatrix4x4 *matrix) const;
+
+Q_SIGNALS:
+ void xChanged();
+ void yChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QSGTranslate)
+ Q_DISABLE_COPY(QSGTranslate)
+};
+
+class QSGScalePrivate;
+class Q_AUTOTEST_EXPORT QSGScale : public QSGTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVector3D origin READ origin WRITE setOrigin NOTIFY originChanged)
+ 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)
+public:
+ QSGScale(QObject *parent = 0);
+ ~QSGScale();
+
+ QVector3D origin() const;
+ void setOrigin(const QVector3D &point);
+
+ qreal xScale() const;
+ void setXScale(qreal);
+
+ qreal yScale() const;
+ void setYScale(qreal);
+
+ qreal zScale() const;
+ void setZScale(qreal);
+
+ void applyTo(QMatrix4x4 *matrix) const;
+
+Q_SIGNALS:
+ void originChanged();
+ void xScaleChanged();
+ void yScaleChanged();
+ void zScaleChanged();
+ void scaleChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QSGScale)
+};
+
+class QSGRotationPrivate;
+class Q_AUTOTEST_EXPORT QSGRotation : public QSGTransform
+{
+ Q_OBJECT
+
+ 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)
+public:
+ QSGRotation(QObject *parent = 0);
+ ~QSGRotation();
+
+ QVector3D origin() const;
+ void setOrigin(const QVector3D &point);
+
+ qreal angle() const;
+ void setAngle(qreal);
+
+ QVector3D axis() const;
+ void setAxis(const QVector3D &axis);
+ void setAxis(Qt::Axis axis);
+
+ void applyTo(QMatrix4x4 *matrix) const;
+
+Q_SIGNALS:
+ void originChanged();
+ void angleChanged();
+ void axisChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QSGRotation)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGTranslate)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/items/qsgview.cpp b/src/declarative/items/qsgview.cpp
new file mode 100644
index 0000000000..1169c59a1b
--- /dev/null
+++ b/src/declarative/items/qsgview.cpp
@@ -0,0 +1,466 @@
+// Commit: 55c4d94dfea78951f3371d3697a3cb28539b3012
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgview.h"
+
+#include "qsgcanvas_p.h"
+#include "qsgitem_p.h"
+#include "qsgitemchangelistener_p.h"
+
+#include <private/qdeclarativedebugtrace_p.h>
+
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <private/qdeclarativeengine_p.h>
+#include <QtCore/qbasictimer.h>
+
+// XXX todo - This whole class should probably be merged with QDeclarativeView for
+// maximum seamlessness
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE)
+
+class QSGViewPrivate : public QSGCanvasPrivate,
+ public QSGItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QSGView)
+public:
+ QSGViewPrivate();
+ ~QSGViewPrivate();
+
+ void execute();
+ void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
+ void initResize();
+ void updateSize();
+ void setRootObject(QObject *);
+
+ void init();
+
+ QSize rootObjectSize() const;
+
+ QPointer<QSGItem> root;
+
+ QUrl source;
+
+ QDeclarativeEngine engine;
+ QDeclarativeComponent *component;
+ QBasicTimer resizetimer;
+
+ QSGView::ResizeMode resizeMode;
+ QSize initialSize;
+ QElapsedTimer frameTimer;
+};
+
+void QSGViewPrivate::init()
+{
+ q_func()->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
+ QDeclarativeEnginePrivate::get(&engine)->sgContext = QSGCanvasPrivate::context;
+}
+
+QSGViewPrivate::QSGViewPrivate()
+: root(0), component(0), resizeMode(QSGView::SizeViewToRootObject), initialSize(0,0)
+{
+}
+
+QSGViewPrivate::~QSGViewPrivate()
+{
+ delete root;
+}
+
+void QSGViewPrivate::execute()
+{
+ Q_Q(QSGView);
+ if (root) {
+ delete root;
+ root = 0;
+ }
+ if (component) {
+ delete component;
+ component = 0;
+ }
+ if (!source.isEmpty()) {
+ component = new QDeclarativeComponent(&engine, source, q);
+ if (!component->isLoading()) {
+ q->continueExecute();
+ } else {
+ QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
+ q, SLOT(continueExecute()));
+ }
+ }
+}
+
+void QSGViewPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_Q(QSGView);
+ if (resizeItem == root && resizeMode == QSGView::SizeViewToRootObject) {
+ // wait for both width and height to be changed
+ resizetimer.start(0,q);
+ }
+ QSGItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
+}
+
+QSGView::QSGView(QWidget *parent, Qt::WindowFlags f)
+: QSGCanvas(*(new QSGViewPrivate), parent, f)
+{
+ d_func()->init();
+}
+
+QSGView::QSGView(const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
+: QSGCanvas(*(new QSGViewPrivate), format, parent, f)
+{
+ d_func()->init();
+}
+
+QSGView::QSGView(const QUrl &source, QWidget *parent, Qt::WindowFlags f)
+: QSGCanvas(*(new QSGViewPrivate), parent, f)
+{
+ d_func()->init();
+ setSource(source);
+}
+
+QSGView::QSGView(const QUrl &source, const QGLFormat &format, QWidget *parent, Qt::WindowFlags f)
+: QSGCanvas(*(new QSGViewPrivate), format, parent, f)
+{
+ d_func()->init();
+ setSource(source);
+}
+
+QSGView::~QSGView()
+{
+}
+
+void QSGView::setSource(const QUrl& url)
+{
+ Q_D(QSGView);
+ d->source = url;
+ d->execute();
+}
+
+QUrl QSGView::source() const
+{
+ Q_D(const QSGView);
+ return d->source;
+}
+
+QDeclarativeEngine* QSGView::engine() const
+{
+ Q_D(const QSGView);
+ return const_cast<QDeclarativeEngine *>(&d->engine);
+}
+
+QDeclarativeContext* QSGView::rootContext() const
+{
+ Q_D(const QSGView);
+ return d->engine.rootContext();
+}
+
+QSGView::Status QSGView::status() const
+{
+ Q_D(const QSGView);
+ if (!d->component)
+ return QSGView::Null;
+
+ return QSGView::Status(d->component->status());
+}
+
+QList<QDeclarativeError> QSGView::errors() const
+{
+ Q_D(const QSGView);
+ if (d->component)
+ return d->component->errors();
+ return QList<QDeclarativeError>();
+}
+
+void QSGView::setResizeMode(ResizeMode mode)
+{
+ Q_D(QSGView);
+ if (d->resizeMode == mode)
+ return;
+
+ if (d->root) {
+ if (d->resizeMode == SizeViewToRootObject) {
+ QSGItemPrivate *p = QSGItemPrivate::get(d->root);
+ p->removeItemChangeListener(d, QSGItemPrivate::Geometry);
+ }
+ }
+
+ d->resizeMode = mode;
+ if (d->root) {
+ d->initResize();
+ }
+}
+
+void QSGViewPrivate::initResize()
+{
+ if (root) {
+ if (resizeMode == QSGView::SizeViewToRootObject) {
+ QSGItemPrivate *p = QSGItemPrivate::get(root);
+ p->addItemChangeListener(this, QSGItemPrivate::Geometry);
+ }
+ }
+ updateSize();
+}
+
+void QSGViewPrivate::updateSize()
+{
+ Q_Q(QSGView);
+ if (!root)
+ return;
+
+ if (resizeMode == QSGView::SizeViewToRootObject) {
+ QSize newSize = QSize(root->width(), root->height());
+ if (newSize.isValid() && newSize != q->size()) {
+ q->resize(newSize);
+ }
+ } else if (resizeMode == QSGView::SizeRootObjectToView) {
+ if (!qFuzzyCompare(q->width(), root->width()))
+ root->setWidth(q->width());
+ if (!qFuzzyCompare(q->height(), root->height()))
+ root->setHeight(q->height());
+ }
+
+ q->updateGeometry();
+}
+
+QSize QSGViewPrivate::rootObjectSize() const
+{
+ QSize rootObjectSize(0,0);
+ int widthCandidate = -1;
+ int heightCandidate = -1;
+ if (root) {
+ widthCandidate = root->width();
+ heightCandidate = root->height();
+ }
+ if (widthCandidate > 0) {
+ rootObjectSize.setWidth(widthCandidate);
+ }
+ if (heightCandidate > 0) {
+ rootObjectSize.setHeight(heightCandidate);
+ }
+ return rootObjectSize;
+}
+
+QSGView::ResizeMode QSGView::resizeMode() const
+{
+ Q_D(const QSGView);
+ return d->resizeMode;
+}
+
+/*!
+ \internal
+ */
+void QSGView::continueExecute()
+{
+ Q_D(QSGView);
+ disconnect(d->component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), this, SLOT(continueExecute()));
+
+ if (d->component->isError()) {
+ QList<QDeclarativeError> errorList = d->component->errors();
+ foreach (const QDeclarativeError &error, errorList) {
+ qWarning() << error;
+ }
+ emit statusChanged(status());
+ return;
+ }
+
+ QObject *obj = d->component->create();
+
+ if(d->component->isError()) {
+ QList<QDeclarativeError> errorList = d->component->errors();
+ foreach (const QDeclarativeError &error, errorList) {
+ qWarning() << error;
+ }
+ emit statusChanged(status());
+ return;
+ }
+
+ d->setRootObject(obj);
+ emit statusChanged(status());
+}
+
+
+/*!
+ \internal
+*/
+void QSGViewPrivate::setRootObject(QObject *obj)
+{
+ Q_Q(QSGView);
+ if (root == obj)
+ return;
+ if (QSGItem *sgItem = qobject_cast<QSGItem *>(obj)) {
+ root = sgItem;
+ sgItem->setParentItem(q->QSGCanvas::rootItem());
+ } else {
+ qWarning() << "QSGView only supports loading of root objects that derive from QSGItem." << endl
+ << endl
+ << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl
+ << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl
+ << endl
+ << "To load files with 'import QtQuick 1.0' with QML 2, specify:" << endl
+ << " QMLSCENE_IMPORT_NAME=quick1" << endl
+ << "on as an environment variable prior to launching the application." << endl
+ << endl
+ << "To load files with 'import Qt 4.7' with QML 2, specify:" << endl
+ << " QMLSCENE_IMPORT_NAME=qt" << endl
+ << "on as an environment variable prior to launching the application." << endl;
+ delete obj;
+ root = 0;
+ }
+
+ if (root) {
+ initialSize = rootObjectSize();
+ if (initialSize != q->size()) {
+ if (!(q->parentWidget() && q->parentWidget()->layout())) {
+ q->resize(initialSize);
+ }
+ }
+ initResize();
+ }
+}
+
+/*!
+ \internal
+ If the \l {QTimerEvent} {timer event} \a e is this
+ view's resize timer, sceneResized() is emitted.
+ */
+void QSGView::timerEvent(QTimerEvent* e)
+{
+ Q_D(QSGView);
+ if (!e || e->timerId() == d->resizetimer.timerId()) {
+ d->updateSize();
+ d->resizetimer.stop();
+ }
+}
+
+/*!
+ \internal
+ Preferred size follows the root object geometry.
+*/
+QSize QSGView::sizeHint() const
+{
+ Q_D(const QSGView);
+ QSize rootObjectSize = d->rootObjectSize();
+ if (rootObjectSize.isEmpty()) {
+ return size();
+ } else {
+ return rootObjectSize;
+ }
+}
+
+QSize QSGView::initialSize() const
+{
+ Q_D(const QSGView);
+ return d->initialSize;
+}
+
+QSGItem *QSGView::rootObject() const
+{
+ Q_D(const QSGView);
+ return d->root;
+}
+
+/*!
+ \internal
+ This function handles the \l {QResizeEvent} {resize event}
+ \a e.
+ */
+void QSGView::resizeEvent(QResizeEvent *e)
+{
+ Q_D(QSGView);
+ if (d->resizeMode == SizeRootObjectToView)
+ d->updateSize();
+
+ QSGCanvas::resizeEvent(e);
+}
+
+/*!
+ \internal
+*/
+void QSGView::paintEvent(QPaintEvent *event)
+{
+ Q_D(QSGView);
+ int time = 0;
+ if (frameRateDebug())
+ time = d->frameTimer.restart();
+
+ QSGCanvas::paintEvent(event);
+
+ if (frameRateDebug())
+ qDebug() << "paintEvent:" << d->frameTimer.elapsed() << "time since last frame:" << time;
+}
+
+void QSGView::keyPressEvent(QKeyEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
+
+ QSGCanvas::keyPressEvent(e);
+}
+
+void QSGView::keyReleaseEvent(QKeyEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
+
+ QSGCanvas::keyReleaseEvent(e);
+}
+
+void QSGView::mouseMoveEvent(QMouseEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
+
+ QSGCanvas::mouseMoveEvent(e);
+}
+
+void QSGView::mousePressEvent(QMouseEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
+
+ QSGCanvas::mousePressEvent(e);
+}
+
+void QSGView::mouseReleaseEvent(QMouseEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
+
+ QSGCanvas::mouseReleaseEvent(e);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/items/qsgview.h b/src/declarative/items/qsgview.h
new file mode 100644
index 0000000000..8e174b7170
--- /dev/null
+++ b/src/declarative/items/qsgview.h
@@ -0,0 +1,120 @@
+// Commit: 0b83a2161261be525f01359397ab1c8c34827749
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGVIEW_H
+#define QSGVIEW_H
+
+#include <QtCore/qurl.h>
+#include <qsgcanvas.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeEngine;
+class QDeclarativeContext;
+class QDeclarativeError;
+class QSGItem;
+
+class QSGViewPrivate;
+class Q_DECLARATIVE_EXPORT QSGView : public QSGCanvas
+{
+ Q_OBJECT
+ Q_PROPERTY(ResizeMode resizeMode READ resizeMode WRITE setResizeMode)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true)
+ Q_ENUMS(ResizeMode Status)
+public:
+ explicit QSGView(QWidget *parent = 0, Qt::WindowFlags f = 0);
+ explicit QSGView(const QGLFormat &format, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ QSGView(const QUrl &source, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ QSGView(const QUrl &source, const QGLFormat &format, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ virtual ~QSGView();
+
+ QUrl source() const;
+ void setSource(const QUrl&);
+
+ QDeclarativeEngine* engine() const;
+ QDeclarativeContext* rootContext() const;
+
+ QSGItem *rootObject() const;
+
+ enum ResizeMode { SizeViewToRootObject, SizeRootObjectToView };
+ ResizeMode resizeMode() const;
+ void setResizeMode(ResizeMode);
+
+ enum Status { Null, Ready, Loading, Error };
+ Status status() const;
+
+ QList<QDeclarativeError> errors() const;
+
+ QSize sizeHint() const;
+ QSize initialSize() const;
+
+Q_SIGNALS:
+ void statusChanged(QSGView::Status);
+
+private Q_SLOTS:
+ void continueExecute();
+
+protected:
+ virtual void resizeEvent(QResizeEvent *);
+ virtual void paintEvent(QPaintEvent *event);
+ virtual void timerEvent(QTimerEvent*);
+
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void keyReleaseEvent(QKeyEvent *);
+ virtual void mousePressEvent(QMouseEvent *);
+ virtual void mouseReleaseEvent(QMouseEvent *);
+ virtual void mouseMoveEvent(QMouseEvent *);
+private:
+ Q_DISABLE_COPY(QSGView)
+ Q_DECLARE_PRIVATE(QSGView)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGVIEW_H
diff --git a/src/declarative/items/qsgvisualitemmodel.cpp b/src/declarative/items/qsgvisualitemmodel.cpp
new file mode 100644
index 0000000000..c7628b230e
--- /dev/null
+++ b/src/declarative/items/qsgvisualitemmodel.cpp
@@ -0,0 +1,1247 @@
+// Commit: 45153a37e4d9e39e8c326a0f33ea17be49bb29e2
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgvisualitemmodel_p.h"
+#include "qsgitem.h"
+
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+
+#include <private/qdeclarativecontext_p.h>
+#include <private/qdeclarativepackage_p.h>
+#include <private/qdeclarativeopenmetaobject_p.h>
+#include <private/qdeclarativelistaccessor_p.h>
+#include <private/qdeclarativedata_p.h>
+#include <private/qdeclarativepropertycache_p.h>
+#include <private/qdeclarativeguard_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qlistmodelinterface_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+#include <private/qobject_p.h>
+
+#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+QHash<QObject*, QSGVisualItemModelAttached*> QSGVisualItemModelAttached::attachedProperties;
+
+
+class QSGVisualItemModelPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGVisualItemModel)
+public:
+ QSGVisualItemModelPrivate() : QObjectPrivate() {}
+
+ static void children_append(QDeclarativeListProperty<QSGItem> *prop, QSGItem *item) {
+ QDeclarative_setParent_noEvent(item, prop->object);
+ static_cast<QSGVisualItemModelPrivate *>(prop->data)->children.append(Item(item));
+ static_cast<QSGVisualItemModelPrivate *>(prop->data)->itemAppended();
+ static_cast<QSGVisualItemModelPrivate *>(prop->data)->emitChildrenChanged();
+ }
+
+ static int children_count(QDeclarativeListProperty<QSGItem> *prop) {
+ return static_cast<QSGVisualItemModelPrivate *>(prop->data)->children.count();
+ }
+
+ static QSGItem *children_at(QDeclarativeListProperty<QSGItem> *prop, int index) {
+ return static_cast<QSGVisualItemModelPrivate *>(prop->data)->children.at(index).item;
+ }
+
+ void itemAppended() {
+ Q_Q(QSGVisualItemModel);
+ QSGVisualItemModelAttached *attached = QSGVisualItemModelAttached::properties(children.last().item);
+ attached->setIndex(children.count()-1);
+ emit q->itemsInserted(children.count()-1, 1);
+ emit q->countChanged();
+ }
+
+ void emitChildrenChanged() {
+ Q_Q(QSGVisualItemModel);
+ emit q->childrenChanged();
+ }
+
+ int indexOf(QSGItem *item) const {
+ for (int i = 0; i < children.count(); ++i)
+ if (children.at(i).item == item)
+ return i;
+ return -1;
+ }
+
+ class Item {
+ public:
+ Item(QSGItem *i) : item(i), ref(0) {}
+
+ void addRef() { ++ref; }
+ bool deref() { return --ref == 0; }
+
+ QSGItem *item;
+ int ref;
+ };
+
+ QList<Item> children;
+};
+
+QSGVisualItemModel::QSGVisualItemModel(QObject *parent)
+ : QSGVisualModel(*(new QSGVisualItemModelPrivate), parent)
+{
+}
+
+QDeclarativeListProperty<QSGItem> QSGVisualItemModel::children()
+{
+ Q_D(QSGVisualItemModel);
+ return QDeclarativeListProperty<QSGItem>(this, d, d->children_append,
+ d->children_count, d->children_at);
+}
+
+int QSGVisualItemModel::count() const
+{
+ Q_D(const QSGVisualItemModel);
+ return d->children.count();
+}
+
+bool QSGVisualItemModel::isValid() const
+{
+ return true;
+}
+
+QSGItem *QSGVisualItemModel::item(int index, bool)
+{
+ Q_D(QSGVisualItemModel);
+ QSGVisualItemModelPrivate::Item &item = d->children[index];
+ item.addRef();
+ return item.item;
+}
+
+QSGVisualModel::ReleaseFlags QSGVisualItemModel::release(QSGItem *item)
+{
+ Q_D(QSGVisualItemModel);
+ int idx = d->indexOf(item);
+ if (idx >= 0) {
+ if (d->children[idx].deref()) {
+ // XXX todo - the original did item->scene()->removeItem(). Why?
+ item->setParentItem(0);
+ QDeclarative_setParent_noEvent(item, this);
+ }
+ }
+ return 0;
+}
+
+bool QSGVisualItemModel::completePending() const
+{
+ return false;
+}
+
+void QSGVisualItemModel::completeItem()
+{
+ // Nothing to do
+}
+
+QString QSGVisualItemModel::stringValue(int index, const QString &name)
+{
+ Q_D(QSGVisualItemModel);
+ if (index < 0 || index >= d->children.count())
+ return QString();
+ return QDeclarativeEngine::contextForObject(d->children.at(index).item)->contextProperty(name).toString();
+}
+
+int QSGVisualItemModel::indexOf(QSGItem *item, QObject *) const
+{
+ Q_D(const QSGVisualItemModel);
+ return d->indexOf(item);
+}
+
+QSGVisualItemModelAttached *QSGVisualItemModel::qmlAttachedProperties(QObject *obj)
+{
+ return QSGVisualItemModelAttached::properties(obj);
+}
+
+//============================================================================
+
+class VDMDelegateDataType : public QDeclarativeOpenMetaObjectType
+{
+public:
+ VDMDelegateDataType(const QMetaObject *base, QDeclarativeEngine *engine) : QDeclarativeOpenMetaObjectType(base, engine) {}
+
+ void propertyCreated(int, QMetaPropertyBuilder &prop) {
+ prop.setWritable(false);
+ }
+};
+
+class QSGVisualDataModelParts;
+class QSGVisualDataModelData;
+class QSGVisualDataModelPrivate : public QObjectPrivate
+{
+public:
+ QSGVisualDataModelPrivate(QDeclarativeContext *);
+
+ static QSGVisualDataModelPrivate *get(QSGVisualDataModel *m) {
+ return static_cast<QSGVisualDataModelPrivate *>(QObjectPrivate::get(m));
+ }
+
+ QDeclarativeGuard<QListModelInterface> m_listModelInterface;
+ QDeclarativeGuard<QAbstractItemModel> m_abstractItemModel;
+ QDeclarativeGuard<QSGVisualDataModel> m_visualItemModel;
+ QString m_part;
+
+ QDeclarativeComponent *m_delegate;
+ QDeclarativeGuard<QDeclarativeContext> m_context;
+ QList<int> m_roles;
+ QHash<QByteArray,int> m_roleNames;
+ void ensureRoles() {
+ if (m_roleNames.isEmpty()) {
+ if (m_listModelInterface) {
+ m_roles = m_listModelInterface->roles();
+ for (int ii = 0; ii < m_roles.count(); ++ii)
+ m_roleNames.insert(m_listModelInterface->toString(m_roles.at(ii)).toUtf8(), m_roles.at(ii));
+ } else if (m_abstractItemModel) {
+ for (QHash<int,QByteArray>::const_iterator it = m_abstractItemModel->roleNames().begin();
+ it != m_abstractItemModel->roleNames().end(); ++it) {
+ m_roles.append(it.key());
+ m_roleNames.insert(*it, it.key());
+ }
+ if (m_roles.count())
+ m_roleNames.insert("hasModelChildren", -1);
+ } else if (m_listAccessor) {
+ m_roleNames.insert("modelData", 0);
+ if (m_listAccessor->type() == QDeclarativeListAccessor::Instance) {
+ if (QObject *object = m_listAccessor->at(0).value<QObject*>()) {
+ int count = object->metaObject()->propertyCount();
+ for (int ii = 1; ii < count; ++ii) {
+ const QMetaProperty &prop = object->metaObject()->property(ii);
+ m_roleNames.insert(prop.name(), 0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ QHash<int,int> m_roleToPropId;
+ int m_modelDataPropId;
+ void createMetaData() {
+ if (!m_metaDataCreated) {
+ ensureRoles();
+ if (m_roleNames.count()) {
+ QHash<QByteArray, int>::const_iterator it = m_roleNames.begin();
+ while (it != m_roleNames.end()) {
+ int propId = m_delegateDataType->createProperty(it.key()) - m_delegateDataType->propertyOffset();
+ m_roleToPropId.insert(*it, propId);
+ ++it;
+ }
+ // Add modelData property
+ if (m_roles.count() == 1)
+ m_modelDataPropId = m_delegateDataType->createProperty("modelData") - m_delegateDataType->propertyOffset();
+ m_metaDataCreated = true;
+ }
+ }
+ }
+
+ struct ObjectRef {
+ ObjectRef(QObject *object=0) : obj(object), ref(1) {}
+ QObject *obj;
+ int ref;
+ };
+ class Cache : public QHash<int, ObjectRef> {
+ public:
+ QObject *getItem(int index) {
+ QObject *item = 0;
+ QHash<int,ObjectRef>::iterator it = find(index);
+ if (it != end()) {
+ (*it).ref++;
+ item = (*it).obj;
+ }
+ return item;
+ }
+ QObject *item(int index) {
+ QObject *item = 0;
+ QHash<int, ObjectRef>::const_iterator it = find(index);
+ if (it != end())
+ item = (*it).obj;
+ return item;
+ }
+ void insertItem(int index, QObject *obj) {
+ insert(index, ObjectRef(obj));
+ }
+ bool releaseItem(QObject *obj) {
+ QHash<int, ObjectRef>::iterator it = begin();
+ for (; it != end(); ++it) {
+ ObjectRef &objRef = *it;
+ if (objRef.obj == obj) {
+ if (--objRef.ref == 0) {
+ erase(it);
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+ };
+
+ int modelCount() const {
+ if (m_visualItemModel)
+ return m_visualItemModel->count();
+ if (m_listModelInterface)
+ return m_listModelInterface->count();
+ if (m_abstractItemModel)
+ return m_abstractItemModel->rowCount(m_root);
+ if (m_listAccessor)
+ return m_listAccessor->count();
+ return 0;
+ }
+
+ Cache m_cache;
+ QHash<QObject *, QDeclarativePackage*> m_packaged;
+
+ QSGVisualDataModelParts *m_parts;
+ friend class QSGVisualItemParts;
+
+ VDMDelegateDataType *m_delegateDataType;
+ friend class QSGVisualDataModelData;
+ bool m_metaDataCreated : 1;
+ bool m_metaDataCacheable : 1;
+ bool m_delegateValidated : 1;
+ bool m_completePending : 1;
+
+ QSGVisualDataModelData *data(QObject *item);
+
+ QVariant m_modelVariant;
+ QDeclarativeListAccessor *m_listAccessor;
+
+ QModelIndex m_root;
+ QList<QByteArray> watchedRoles;
+ QList<int> watchedRoleIds;
+};
+
+class QSGVisualDataModelDataMetaObject : public QDeclarativeOpenMetaObject
+{
+public:
+ QSGVisualDataModelDataMetaObject(QObject *parent, QDeclarativeOpenMetaObjectType *type)
+ : QDeclarativeOpenMetaObject(parent, type) {}
+
+ virtual QVariant initialValue(int);
+ virtual int createProperty(const char *, const char *);
+
+private:
+ friend class QSGVisualDataModelData;
+};
+
+class QSGVisualDataModelData : public QObject
+{
+Q_OBJECT
+public:
+ QSGVisualDataModelData(int index, QSGVisualDataModel *model);
+ ~QSGVisualDataModelData();
+
+ Q_PROPERTY(int index READ index NOTIFY indexChanged)
+ int index() const;
+ void setIndex(int index);
+
+ int propForRole(int) const;
+ int modelDataPropertyId() const {
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model);
+ return model->m_modelDataPropId;
+ }
+
+ void setValue(int, const QVariant &);
+ bool hasValue(int id) const {
+ return m_meta->hasValue(id);
+ }
+
+ void ensureProperties();
+
+Q_SIGNALS:
+ void indexChanged();
+
+private:
+ friend class QSGVisualDataModelDataMetaObject;
+ int m_index;
+ QDeclarativeGuard<QSGVisualDataModel> m_model;
+ QSGVisualDataModelDataMetaObject *m_meta;
+};
+
+int QSGVisualDataModelData::propForRole(int id) const
+{
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model);
+ QHash<int,int>::const_iterator it = model->m_roleToPropId.find(id);
+ if (it != model->m_roleToPropId.end())
+ return *it;
+
+ return -1;
+}
+
+void QSGVisualDataModelData::setValue(int id, const QVariant &val)
+{
+ m_meta->setValue(id, val);
+}
+
+int QSGVisualDataModelDataMetaObject::createProperty(const char *name, const char *type)
+{
+ QSGVisualDataModelData *data =
+ static_cast<QSGVisualDataModelData *>(object());
+
+ if (!data->m_model)
+ return -1;
+
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(data->m_model);
+ if (data->m_index < 0 || data->m_index >= model->modelCount())
+ return -1;
+
+ if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) {
+ if (model->m_listAccessor->type() == QDeclarativeListAccessor::ListProperty) {
+ model->ensureRoles();
+ if (qstrcmp(name,"modelData") == 0)
+ return QDeclarativeOpenMetaObject::createProperty(name, type);
+ }
+ }
+ return -1;
+}
+
+QVariant QSGVisualDataModelDataMetaObject::initialValue(int propId)
+{
+ QSGVisualDataModelData *data =
+ static_cast<QSGVisualDataModelData *>(object());
+
+ Q_ASSERT(data->m_model);
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(data->m_model);
+
+ QByteArray propName = name(propId);
+ if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) {
+ if (propName == "modelData") {
+ if (model->m_listAccessor->type() == QDeclarativeListAccessor::Instance) {
+ QObject *object = model->m_listAccessor->at(0).value<QObject*>();
+ return object->metaObject()->property(1).read(object); // the first property after objectName
+ }
+ return model->m_listAccessor->at(data->m_index);
+ } else {
+ // return any property of a single object instance.
+ QObject *object = model->m_listAccessor->at(data->m_index).value<QObject*>();
+ return object->property(propName);
+ }
+ } else if (model->m_listModelInterface) {
+ model->ensureRoles();
+ QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName);
+ if (it != model->m_roleNames.end()) {
+ QVariant value = model->m_listModelInterface->data(data->m_index, *it);
+ return value;
+ } else if (model->m_roles.count() == 1 && propName == "modelData") {
+ //for compatibility with other lists, assign modelData if there is only a single role
+ QVariant value = model->m_listModelInterface->data(data->m_index, model->m_roles.first());
+ return value;
+ }
+ } else if (model->m_abstractItemModel) {
+ model->ensureRoles();
+ QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0, model->m_root);
+ if (propName == "hasModelChildren") {
+ return model->m_abstractItemModel->hasChildren(index);
+ } else {
+ QHash<QByteArray,int>::const_iterator it = model->m_roleNames.find(propName);
+ if (it != model->m_roleNames.end()) {
+ return model->m_abstractItemModel->data(index, *it);
+ } else if (model->m_roles.count() == 1 && propName == "modelData") {
+ //for compatibility with other lists, assign modelData if there is only a single role
+ return model->m_abstractItemModel->data(index, model->m_roles.first());
+ }
+ }
+ }
+ Q_ASSERT(!"Can never be reached");
+ return QVariant();
+}
+
+QSGVisualDataModelData::QSGVisualDataModelData(int index,
+ QSGVisualDataModel *model)
+: m_index(index), m_model(model),
+m_meta(new QSGVisualDataModelDataMetaObject(this, QSGVisualDataModelPrivate::get(model)->m_delegateDataType))
+{
+ ensureProperties();
+}
+
+QSGVisualDataModelData::~QSGVisualDataModelData()
+{
+}
+
+void QSGVisualDataModelData::ensureProperties()
+{
+ QSGVisualDataModelPrivate *modelPriv = QSGVisualDataModelPrivate::get(m_model);
+ if (modelPriv->m_metaDataCacheable) {
+ if (!modelPriv->m_metaDataCreated)
+ modelPriv->createMetaData();
+ if (modelPriv->m_metaDataCreated)
+ m_meta->setCached(true);
+ }
+}
+
+int QSGVisualDataModelData::index() const
+{
+ return m_index;
+}
+
+// This is internal only - it should not be set from qml
+void QSGVisualDataModelData::setIndex(int index)
+{
+ m_index = index;
+ emit indexChanged();
+}
+
+//---------------------------------------------------------------------------
+
+class QSGVisualDataModelPartsMetaObject : public QDeclarativeOpenMetaObject
+{
+public:
+ QSGVisualDataModelPartsMetaObject(QObject *parent)
+ : QDeclarativeOpenMetaObject(parent) {}
+
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+ virtual QVariant initialValue(int);
+};
+
+class QSGVisualDataModelParts : public QObject
+{
+Q_OBJECT
+public:
+ QSGVisualDataModelParts(QSGVisualDataModel *parent);
+
+private:
+ friend class QSGVisualDataModelPartsMetaObject;
+ QSGVisualDataModel *model;
+};
+
+void QSGVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
+{
+ prop.setWritable(false);
+}
+
+QVariant QSGVisualDataModelPartsMetaObject::initialValue(int id)
+{
+ QSGVisualDataModel *m = new QSGVisualDataModel;
+ m->setParent(object());
+ m->setPart(QString::fromUtf8(name(id)));
+ m->setModel(QVariant::fromValue(static_cast<QSGVisualDataModelParts *>(object())->model));
+
+ QVariant var = QVariant::fromValue((QObject *)m);
+ return var;
+}
+
+QSGVisualDataModelParts::QSGVisualDataModelParts(QSGVisualDataModel *parent)
+: QObject(parent), model(parent)
+{
+ new QSGVisualDataModelPartsMetaObject(this);
+}
+
+QSGVisualDataModelPrivate::QSGVisualDataModelPrivate(QDeclarativeContext *ctxt)
+: m_listModelInterface(0), m_abstractItemModel(0), m_visualItemModel(0), m_delegate(0)
+, m_context(ctxt), m_modelDataPropId(-1), m_parts(0), m_delegateDataType(0), m_metaDataCreated(false)
+, m_metaDataCacheable(false), m_delegateValidated(false), m_completePending(false), m_listAccessor(0)
+{
+}
+
+QSGVisualDataModelData *QSGVisualDataModelPrivate::data(QObject *item)
+{
+ QSGVisualDataModelData *dataItem =
+ item->findChild<QSGVisualDataModelData *>();
+ Q_ASSERT(dataItem);
+ return dataItem;
+}
+
+//---------------------------------------------------------------------------
+
+QSGVisualDataModel::QSGVisualDataModel()
+: QSGVisualModel(*(new QSGVisualDataModelPrivate(0)))
+{
+}
+
+QSGVisualDataModel::QSGVisualDataModel(QDeclarativeContext *ctxt, QObject *parent)
+: QSGVisualModel(*(new QSGVisualDataModelPrivate(ctxt)), parent)
+{
+}
+
+QSGVisualDataModel::~QSGVisualDataModel()
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_listAccessor)
+ delete d->m_listAccessor;
+ if (d->m_delegateDataType)
+ d->m_delegateDataType->release();
+}
+
+QVariant QSGVisualDataModel::model() const
+{
+ Q_D(const QSGVisualDataModel);
+ return d->m_modelVariant;
+}
+
+void QSGVisualDataModel::setModel(const QVariant &model)
+{
+ Q_D(QSGVisualDataModel);
+ delete d->m_listAccessor;
+ d->m_listAccessor = 0;
+ d->m_modelVariant = model;
+ if (d->m_listModelInterface) {
+ // Assume caller has released all items.
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
+ this, SLOT(_q_itemsChanged(int,int,QList<int>)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
+ this, SLOT(_q_itemsInserted(int,int)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
+ this, SLOT(_q_itemsRemoved(int,int)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
+ this, SLOT(_q_itemsMoved(int,int,int)));
+ d->m_listModelInterface = 0;
+ } else if (d->m_abstractItemModel) {
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
+ this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset()));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
+ d->m_abstractItemModel = 0;
+ } else if (d->m_visualItemModel) {
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
+ this, SIGNAL(itemsInserted(int,int)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
+ this, SIGNAL(itemsRemoved(int,int)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)),
+ this, SIGNAL(itemsMoved(int,int,int)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(createdPackage(int,QDeclarativePackage*)),
+ this, SLOT(_q_createdPackage(int,QDeclarativePackage*)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(destroyingPackage(QDeclarativePackage*)),
+ this, SLOT(_q_destroyingPackage(QDeclarativePackage*)));
+ d->m_visualItemModel = 0;
+ }
+
+ d->m_roles.clear();
+ d->m_roleNames.clear();
+ if (d->m_delegateDataType)
+ d->m_delegateDataType->release();
+ d->m_metaDataCreated = 0;
+ d->m_metaDataCacheable = false;
+ d->m_delegateDataType = new VDMDelegateDataType(&QSGVisualDataModelData::staticMetaObject, d->m_context?d->m_context->engine():qmlEngine(this));
+
+ QObject *object = qvariant_cast<QObject *>(model);
+ if (object && (d->m_listModelInterface = qobject_cast<QListModelInterface *>(object))) {
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
+ this, SLOT(_q_itemsChanged(int,int,QList<int>)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
+ this, SLOT(_q_itemsInserted(int,int)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
+ this, SLOT(_q_itemsRemoved(int,int)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
+ this, SLOT(_q_itemsMoved(int,int,int)));
+ d->m_metaDataCacheable = true;
+ if (d->m_delegate && d->m_listModelInterface->count())
+ emit itemsInserted(0, d->m_listModelInterface->count());
+ return;
+ } else if (object && (d->m_abstractItemModel = qobject_cast<QAbstractItemModel *>(object))) {
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
+ this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset()));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
+ d->m_metaDataCacheable = true;
+ if (d->m_abstractItemModel->canFetchMore(d->m_root))
+ d->m_abstractItemModel->fetchMore(d->m_root);
+ return;
+ }
+ if ((d->m_visualItemModel = qvariant_cast<QSGVisualDataModel *>(model))) {
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
+ this, SIGNAL(itemsInserted(int,int)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
+ this, SIGNAL(itemsRemoved(int,int)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)),
+ this, SIGNAL(itemsMoved(int,int,int)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(createdPackage(int,QDeclarativePackage*)),
+ this, SLOT(_q_createdPackage(int,QDeclarativePackage*)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(destroyingPackage(QDeclarativePackage*)),
+ this, SLOT(_q_destroyingPackage(QDeclarativePackage*)));
+ return;
+ }
+ d->m_listAccessor = new QDeclarativeListAccessor;
+ d->m_listAccessor->setList(model, d->m_context?d->m_context->engine():qmlEngine(this));
+ if (d->m_listAccessor->type() != QDeclarativeListAccessor::ListProperty)
+ d->m_metaDataCacheable = true;
+ if (d->m_delegate && d->modelCount()) {
+ emit itemsInserted(0, d->modelCount());
+ emit countChanged();
+ }
+}
+
+QDeclarativeComponent *QSGVisualDataModel::delegate() const
+{
+ Q_D(const QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->delegate();
+ return d->m_delegate;
+}
+
+void QSGVisualDataModel::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QSGVisualDataModel);
+ bool wasValid = d->m_delegate != 0;
+ d->m_delegate = delegate;
+ d->m_delegateValidated = false;
+ if (!wasValid && d->modelCount() && d->m_delegate) {
+ emit itemsInserted(0, d->modelCount());
+ emit countChanged();
+ }
+ if (wasValid && !d->m_delegate && d->modelCount()) {
+ emit itemsRemoved(0, d->modelCount());
+ emit countChanged();
+ }
+}
+
+QVariant QSGVisualDataModel::rootIndex() const
+{
+ Q_D(const QSGVisualDataModel);
+ return QVariant::fromValue(d->m_root);
+}
+
+void QSGVisualDataModel::setRootIndex(const QVariant &root)
+{
+ Q_D(QSGVisualDataModel);
+ QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
+ if (d->m_root != modelIndex) {
+ int oldCount = d->modelCount();
+ d->m_root = modelIndex;
+ if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(modelIndex))
+ d->m_abstractItemModel->fetchMore(modelIndex);
+ int newCount = d->modelCount();
+ if (d->m_delegate && oldCount)
+ emit itemsRemoved(0, oldCount);
+ if (d->m_delegate && newCount)
+ emit itemsInserted(0, newCount);
+ if (newCount != oldCount)
+ emit countChanged();
+ emit rootIndexChanged();
+ }
+}
+
+QVariant QSGVisualDataModel::modelIndex(int idx) const
+{
+ Q_D(const QSGVisualDataModel);
+ if (d->m_abstractItemModel)
+ return QVariant::fromValue(d->m_abstractItemModel->index(idx, 0, d->m_root));
+ return QVariant::fromValue(QModelIndex());
+}
+
+QVariant QSGVisualDataModel::parentModelIndex() const
+{
+ Q_D(const QSGVisualDataModel);
+ if (d->m_abstractItemModel)
+ return QVariant::fromValue(d->m_abstractItemModel->parent(d->m_root));
+ return QVariant::fromValue(QModelIndex());
+}
+
+QString QSGVisualDataModel::part() const
+{
+ Q_D(const QSGVisualDataModel);
+ return d->m_part;
+}
+
+void QSGVisualDataModel::setPart(const QString &part)
+{
+ Q_D(QSGVisualDataModel);
+ d->m_part = part;
+}
+
+int QSGVisualDataModel::count() const
+{
+ Q_D(const QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->count();
+ if (!d->m_delegate)
+ return 0;
+ return d->modelCount();
+}
+
+QSGItem *QSGVisualDataModel::item(int index, bool complete)
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->item(index, d->m_part.toUtf8(), complete);
+ return item(index, QByteArray(), complete);
+}
+
+/*
+ Returns ReleaseStatus flags.
+*/
+QSGVisualDataModel::ReleaseFlags QSGVisualDataModel::release(QSGItem *item)
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->release(item);
+
+ ReleaseFlags stat = 0;
+ QObject *obj = item;
+ bool inPackage = false;
+
+ QHash<QObject*,QDeclarativePackage*>::iterator it = d->m_packaged.find(item);
+ if (it != d->m_packaged.end()) {
+ QDeclarativePackage *package = *it;
+ d->m_packaged.erase(it);
+ if (d->m_packaged.contains(item))
+ stat |= Referenced;
+ inPackage = true;
+ obj = package; // fall through and delete
+ }
+
+ if (d->m_cache.releaseItem(obj)) {
+ // Remove any bindings to avoid warnings due to parent change.
+ QObjectPrivate *p = QObjectPrivate::get(obj);
+ Q_ASSERT(p->declarativeData);
+ QDeclarativeData *d = static_cast<QDeclarativeData*>(p->declarativeData);
+ if (d->ownContext && d->context)
+ d->context->clearContext();
+
+ if (inPackage) {
+ emit destroyingPackage(qobject_cast<QDeclarativePackage*>(obj));
+ } else {
+ // XXX todo - the original did item->scene()->removeItem(). Why?
+ item->setParentItem(0);
+ }
+ stat |= Destroyed;
+ obj->deleteLater();
+ } else if (!inPackage) {
+ stat |= Referenced;
+ }
+
+ return stat;
+}
+
+QObject *QSGVisualDataModel::parts()
+{
+ Q_D(QSGVisualDataModel);
+ if (!d->m_parts)
+ d->m_parts = new QSGVisualDataModelParts(this);
+ return d->m_parts;
+}
+
+QSGItem *QSGVisualDataModel::item(int index, const QByteArray &viewId, bool complete)
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->item(index, viewId, complete);
+
+ if (d->modelCount() <= 0 || !d->m_delegate)
+ return 0;
+ QObject *nobj = d->m_cache.getItem(index);
+ bool needComplete = false;
+ if (!nobj) {
+ QDeclarativeContext *ccontext = d->m_context;
+ if (!ccontext) ccontext = qmlContext(this);
+ QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext);
+ QSGVisualDataModelData *data = new QSGVisualDataModelData(index, this);
+ if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor
+ && d->m_listAccessor->type() == QDeclarativeListAccessor::ListProperty) {
+ ctxt->setContextObject(d->m_listAccessor->at(index).value<QObject*>());
+ ctxt = new QDeclarativeContext(ctxt, ctxt);
+ }
+ ctxt->setContextProperty(QLatin1String("model"), data);
+ ctxt->setContextObject(data);
+ d->m_completePending = false;
+ nobj = d->m_delegate->beginCreate(ctxt);
+ if (complete) {
+ d->m_delegate->completeCreate();
+ } else {
+ d->m_completePending = true;
+ needComplete = true;
+ }
+ if (nobj) {
+ QDeclarative_setParent_noEvent(ctxt, nobj);
+ QDeclarative_setParent_noEvent(data, nobj);
+ d->m_cache.insertItem(index, nobj);
+ if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(nobj))
+ emit createdPackage(index, package);
+ } else {
+ delete data;
+ delete ctxt;
+ qmlInfo(this, d->m_delegate->errors()) << "Error creating delegate";
+ }
+ }
+ QSGItem *item = qobject_cast<QSGItem *>(nobj);
+ if (!item) {
+ QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(nobj);
+ if (package) {
+ QObject *o = package->part(QString::fromUtf8(viewId));
+ item = qobject_cast<QSGItem *>(o);
+ if (item)
+ d->m_packaged.insertMulti(item, package);
+ }
+ }
+ if (!item) {
+ if (needComplete)
+ d->m_delegate->completeCreate();
+ d->m_cache.releaseItem(nobj);
+ if (!d->m_delegateValidated) {
+ qmlInfo(d->m_delegate) << QSGVisualDataModel::tr("Delegate component must be Item type.");
+ d->m_delegateValidated = true;
+ }
+ }
+ if (d->modelCount()-1 == index && d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root))
+ d->m_abstractItemModel->fetchMore(d->m_root);
+
+ return item;
+}
+
+bool QSGVisualDataModel::completePending() const
+{
+ Q_D(const QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->completePending();
+ return d->m_completePending;
+}
+
+void QSGVisualDataModel::completeItem()
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_visualItemModel) {
+ d->m_visualItemModel->completeItem();
+ return;
+ }
+
+ d->m_delegate->completeCreate();
+ d->m_completePending = false;
+}
+
+QString QSGVisualDataModel::stringValue(int index, const QString &name)
+{
+ Q_D(QSGVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->stringValue(index, name);
+
+ if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor) {
+ if (QObject *object = d->m_listAccessor->at(index).value<QObject*>())
+ return object->property(name.toUtf8()).toString();
+ }
+
+ if ((!d->m_listModelInterface && !d->m_abstractItemModel) || !d->m_delegate)
+ return QString();
+
+ QString val;
+ QObject *data = 0;
+ bool tempData = false;
+
+ if (QObject *nobj = d->m_cache.item(index))
+ data = d->data(nobj);
+ if (!data) {
+ data = new QSGVisualDataModelData(index, this);
+ tempData = true;
+ }
+
+ QDeclarativeData *ddata = QDeclarativeData::get(data);
+ if (ddata && ddata->propertyCache) {
+ QDeclarativePropertyCache::Data *prop = ddata->propertyCache->property(name);
+ if (prop) {
+ if (prop->propType == QVariant::String) {
+ void *args[] = { &val, 0 };
+ QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args);
+ } else if (prop->propType == qMetaTypeId<QVariant>()) {
+ QVariant v;
+ void *args[] = { &v, 0 };
+ QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args);
+ val = v.toString();
+ }
+ } else {
+ val = data->property(name.toUtf8()).toString();
+ }
+ } else {
+ val = data->property(name.toUtf8()).toString();
+ }
+
+ if (tempData)
+ delete data;
+
+ return val;
+}
+
+int QSGVisualDataModel::indexOf(QSGItem *item, QObject *) const
+{
+ QVariant val = QDeclarativeEngine::contextForObject(item)->contextProperty(QLatin1String("index"));
+ return val.toInt();
+ return -1;
+}
+
+void QSGVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
+{
+ Q_D(QSGVisualDataModel);
+ d->watchedRoles = roles;
+ d->watchedRoleIds.clear();
+}
+
+void QSGVisualDataModel::_q_itemsChanged(int index, int count,
+ const QList<int> &roles)
+{
+ Q_D(QSGVisualDataModel);
+ bool changed = false;
+ if (!d->watchedRoles.isEmpty() && d->watchedRoleIds.isEmpty()) {
+ foreach (QByteArray r, d->watchedRoles) {
+ if (d->m_roleNames.contains(r))
+ d->watchedRoleIds << d->m_roleNames.value(r);
+ }
+ }
+
+ for (QHash<int,QSGVisualDataModelPrivate::ObjectRef>::ConstIterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ++iter) {
+ const int idx = iter.key();
+
+ if (idx >= index && idx < index+count) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ for (int roleIdx = 0; roleIdx < roles.count(); ++roleIdx) {
+ int role = roles.at(roleIdx);
+ if (!changed && !d->watchedRoleIds.isEmpty() && d->watchedRoleIds.contains(role))
+ changed = true;
+ int propId = data->propForRole(role);
+ if (propId != -1) {
+ if (data->hasValue(propId)) {
+ if (d->m_listModelInterface) {
+ data->setValue(propId, d->m_listModelInterface->data(idx, role));
+ } else if (d->m_abstractItemModel) {
+ QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root);
+ data->setValue(propId, d->m_abstractItemModel->data(index, role));
+ }
+ }
+ } else {
+ QString roleName;
+ if (d->m_listModelInterface)
+ roleName = d->m_listModelInterface->toString(role);
+ else if (d->m_abstractItemModel)
+ roleName = QString::fromUtf8(d->m_abstractItemModel->roleNames().value(role));
+ qmlInfo(this) << "Changing role not present in item: " << roleName;
+ }
+ }
+ if (d->m_roles.count() == 1) {
+ // Handle the modelData role we add if there is just one role.
+ int propId = data->modelDataPropertyId();
+ if (data->hasValue(propId)) {
+ int role = d->m_roles.at(0);
+ if (d->m_listModelInterface) {
+ data->setValue(propId, d->m_listModelInterface->data(idx, role));
+ } else if (d->m_abstractItemModel) {
+ QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root);
+ data->setValue(propId, d->m_abstractItemModel->data(index, role));
+ }
+ }
+ }
+ }
+ }
+ if (changed)
+ emit itemsChanged(index, count);
+}
+
+void QSGVisualDataModel::_q_itemsInserted(int index, int count)
+{
+ Q_D(QSGVisualDataModel);
+ if (!count)
+ return;
+ // XXX - highly inefficient
+ QHash<int,QSGVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int,QSGVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if (iter.key() >= index) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() + count;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ d->m_cache.unite(items);
+
+ emit itemsInserted(index, count);
+ emit countChanged();
+}
+
+void QSGVisualDataModel::_q_itemsRemoved(int index, int count)
+{
+ Q_D(QSGVisualDataModel);
+ if (!count)
+ return;
+ // XXX - highly inefficient
+ QHash<int, QSGVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int, QSGVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+ if (iter.key() >= index && iter.key() < index + count) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ iter = d->m_cache.erase(iter);
+ items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(-1);
+ } else if (iter.key() >= index + count) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() - count;
+ iter = d->m_cache.erase(iter);
+ items.insert(index, objRef);
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+
+ d->m_cache.unite(items);
+ emit itemsRemoved(index, count);
+ emit countChanged();
+}
+
+void QSGVisualDataModel::_q_itemsMoved(int from, int to, int count)
+{
+ Q_D(QSGVisualDataModel);
+ // XXX - highly inefficient
+ QHash<int,QSGVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int,QSGVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if (iter.key() >= from && iter.key() < from + count) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() - from + to;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ for (QHash<int,QSGVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ int diff = from > to ? count : -count;
+ if (iter.key() >= qMin(from,to) && iter.key() < qMax(from+count,to+count)) {
+ QSGVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() + diff;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QSGVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ d->m_cache.unite(items);
+
+ emit itemsMoved(from, to, count);
+}
+
+void QSGVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
+{
+ Q_D(QSGVisualDataModel);
+ if (parent == d->m_root)
+ _q_itemsInserted(begin, end - begin + 1);
+}
+
+void QSGVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
+{
+ Q_D(QSGVisualDataModel);
+ if (parent == d->m_root)
+ _q_itemsRemoved(begin, end - begin + 1);
+}
+
+void QSGVisualDataModel::_q_rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
+{
+ Q_D(QSGVisualDataModel);
+ const int count = sourceEnd - sourceStart + 1;
+ if (destinationParent == d->m_root && sourceParent == d->m_root) {
+ _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow-1, count);
+ } else if (sourceParent == d->m_root) {
+ _q_itemsRemoved(sourceStart, count);
+ } else if (destinationParent == d->m_root) {
+ _q_itemsInserted(destinationRow, count);
+ }
+}
+
+void QSGVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
+{
+ Q_D(QSGVisualDataModel);
+ if (begin.parent() == d->m_root)
+ _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles);
+}
+
+void QSGVisualDataModel::_q_layoutChanged()
+{
+ Q_D(QSGVisualDataModel);
+ _q_itemsChanged(0, count(), d->m_roles);
+}
+
+void QSGVisualDataModel::_q_modelReset()
+{
+ emit modelReset();
+}
+
+void QSGVisualDataModel::_q_createdPackage(int index, QDeclarativePackage *package)
+{
+ Q_D(QSGVisualDataModel);
+ emit createdItem(index, qobject_cast<QSGItem*>(package->part(d->m_part)));
+}
+
+void QSGVisualDataModel::_q_destroyingPackage(QDeclarativePackage *package)
+{
+ Q_D(QSGVisualDataModel);
+ emit destroyingItem(qobject_cast<QSGItem*>(package->part(d->m_part)));
+}
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QListModelInterface)
+
+#include <qsgvisualitemmodel.moc>
diff --git a/src/declarative/items/qsgvisualitemmodel_p.h b/src/declarative/items/qsgvisualitemmodel_p.h
new file mode 100644
index 0000000000..1f735e7cbc
--- /dev/null
+++ b/src/declarative/items/qsgvisualitemmodel_p.h
@@ -0,0 +1,257 @@
+// Commit: ac5c099cc3c5b8c7eec7a49fdeb8a21037230350
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGVISUALITEMMODEL_P_H
+#define QSGVISUALITEMMODEL_P_H
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qabstractitemmodel.h>
+
+QT_BEGIN_HEADER
+
+Q_DECLARE_METATYPE(QModelIndex)
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class QDeclarativeComponent;
+class QDeclarativePackage;
+class QSGVisualDataModelPrivate;
+
+class Q_AUTOTEST_EXPORT QSGVisualModel : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+
+public:
+ virtual ~QSGVisualModel() {}
+
+ enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02 };
+ Q_DECLARE_FLAGS(ReleaseFlags, ReleaseFlag)
+
+ virtual int count() const = 0;
+ virtual bool isValid() const = 0;
+ virtual QSGItem *item(int index, bool complete=true) = 0;
+ virtual ReleaseFlags release(QSGItem *item) = 0;
+ virtual bool completePending() const = 0;
+ virtual void completeItem() = 0;
+ virtual QString stringValue(int, const QString &) = 0;
+ virtual void setWatchedRoles(QList<QByteArray> roles) = 0;
+
+ virtual int indexOf(QSGItem *item, QObject *objectContext) const = 0;
+
+Q_SIGNALS:
+ void countChanged();
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int from, int to, int count);
+ void itemsChanged(int index, int count);
+ void modelReset();
+ void createdItem(int index, QSGItem *item);
+ void destroyingItem(QSGItem *item);
+
+protected:
+ QSGVisualModel(QObjectPrivate &dd, QObject *parent = 0)
+ : QObject(dd, parent) {}
+
+private:
+ Q_DISABLE_COPY(QSGVisualModel)
+};
+
+class QSGVisualItemModelAttached;
+class QSGVisualItemModelPrivate;
+class Q_AUTOTEST_EXPORT QSGVisualItemModel : public QSGVisualModel
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGVisualItemModel)
+
+ Q_PROPERTY(QDeclarativeListProperty<QSGItem> children READ children NOTIFY childrenChanged DESIGNABLE false)
+ Q_CLASSINFO("DefaultProperty", "children")
+
+public:
+ QSGVisualItemModel(QObject *parent=0);
+ virtual ~QSGVisualItemModel() {}
+
+ virtual int count() const;
+ virtual bool isValid() const;
+ virtual QSGItem *item(int index, bool complete=true);
+ virtual ReleaseFlags release(QSGItem *item);
+ virtual bool completePending() const;
+ virtual void completeItem();
+ virtual QString stringValue(int index, const QString &role);
+ virtual void setWatchedRoles(QList<QByteArray>) {}
+
+ virtual int indexOf(QSGItem *item, QObject *objectContext) const;
+
+ QDeclarativeListProperty<QSGItem> children();
+
+ static QSGVisualItemModelAttached *qmlAttachedProperties(QObject *obj);
+
+Q_SIGNALS:
+ void childrenChanged();
+
+private:
+ Q_DISABLE_COPY(QSGVisualItemModel)
+};
+
+
+class Q_AUTOTEST_EXPORT QSGVisualDataModel : public QSGVisualModel
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGVisualDataModel)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate)
+ Q_PROPERTY(QString part READ part WRITE setPart)
+ Q_PROPERTY(QObject *parts READ parts CONSTANT)
+ Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
+ Q_CLASSINFO("DefaultProperty", "delegate")
+public:
+ QSGVisualDataModel();
+ QSGVisualDataModel(QDeclarativeContext *, QObject *parent=0);
+ virtual ~QSGVisualDataModel();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ QVariant rootIndex() const;
+ void setRootIndex(const QVariant &root);
+
+ Q_INVOKABLE QVariant modelIndex(int idx) const;
+ Q_INVOKABLE QVariant parentModelIndex() const;
+
+ QString part() const;
+ void setPart(const QString &);
+
+ int count() const;
+ bool isValid() const { return delegate() != 0; }
+ QSGItem *item(int index, bool complete=true);
+ QSGItem *item(int index, const QByteArray &, bool complete=true);
+ ReleaseFlags release(QSGItem *item);
+ bool completePending() const;
+ void completeItem();
+ virtual QString stringValue(int index, const QString &role);
+ virtual void setWatchedRoles(QList<QByteArray> roles);
+
+ int indexOf(QSGItem *item, QObject *objectContext) const;
+
+ QObject *parts();
+
+Q_SIGNALS:
+ void createdPackage(int index, QDeclarativePackage *package);
+ void destroyingPackage(QDeclarativePackage *package);
+ void rootIndexChanged();
+
+private Q_SLOTS:
+ void _q_itemsChanged(int, int, const QList<int> &);
+ void _q_itemsInserted(int index, int count);
+ void _q_itemsRemoved(int index, int count);
+ void _q_itemsMoved(int from, int to, int count);
+ void _q_rowsInserted(const QModelIndex &,int,int);
+ void _q_rowsRemoved(const QModelIndex &,int,int);
+ void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
+ void _q_dataChanged(const QModelIndex&,const QModelIndex&);
+ void _q_layoutChanged();
+ void _q_modelReset();
+ void _q_createdPackage(int index, QDeclarativePackage *package);
+ void _q_destroyingPackage(QDeclarativePackage *package);
+
+private:
+ Q_DISABLE_COPY(QSGVisualDataModel)
+};
+
+class QSGVisualItemModelAttached : public QObject
+{
+ Q_OBJECT
+
+public:
+ QSGVisualItemModelAttached(QObject *parent)
+ : QObject(parent), m_index(0) {}
+ ~QSGVisualItemModelAttached() {
+ attachedProperties.remove(parent());
+ }
+
+ Q_PROPERTY(int index READ index NOTIFY indexChanged)
+ int index() const { return m_index; }
+ void setIndex(int idx) {
+ if (m_index != idx) {
+ m_index = idx;
+ emit indexChanged();
+ }
+ }
+
+ static QSGVisualItemModelAttached *properties(QObject *obj) {
+ QSGVisualItemModelAttached *rv = attachedProperties.value(obj);
+ if (!rv) {
+ rv = new QSGVisualItemModelAttached(obj);
+ attachedProperties.insert(obj, rv);
+ }
+ return rv;
+ }
+
+Q_SIGNALS:
+ void indexChanged();
+
+public:
+ int m_index;
+
+ static QHash<QObject*, QSGVisualItemModelAttached*> attachedProperties;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGVisualModel)
+QML_DECLARE_TYPE(QSGVisualItemModel)
+QML_DECLARE_TYPEINFO(QSGVisualItemModel, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QSGVisualDataModel)
+
+QT_END_HEADER
+
+#endif // QSGVISUALITEMMODEL_P_H
diff --git a/src/declarative/items/syncexcludes b/src/declarative/items/syncexcludes
new file mode 100644
index 0000000000..ab7a374a5b
--- /dev/null
+++ b/src/declarative/items/syncexcludes
@@ -0,0 +1,11 @@
+qdeclarativegraphicswidget.cpp
+qdeclarativegraphicswidget_p.h
+qdeclarativetextlayout_p.h
+qdeclarativetextlayout.cpp
+qdeclarativelayoutitem.cpp
+qdeclarativelayoutitem_p.h
+qdeclarativefocuspanel.cpp
+qdeclarativefocuspanel_p.h
+qdeclarativepath_p.h
+qdeclarativepath_p_p.h
+qdeclarativepath.cpp
diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h
index 5da7901528..9227260b64 100644
--- a/src/declarative/qml/qdeclarative.h
+++ b/src/declarative/qml/qdeclarative.h
@@ -53,6 +53,9 @@
QT_BEGIN_HEADER
+#define QML_VERSION 0x020000
+#define QML_VERSION_STR "2.0"
+
#define QML_DECLARE_TYPE(TYPE) \
Q_DECLARE_METATYPE(TYPE *) \
Q_DECLARE_METATYPE(QDeclarativeListProperty<TYPE>)
@@ -392,6 +395,8 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
class QDeclarativeContext;
class QDeclarativeEngine;
+class QScriptValue;
+class QScriptEngine;
Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *);
Q_DECLARATIVE_EXPORT QDeclarativeContext *qmlContext(const QObject *);
Q_DECLARATIVE_EXPORT QDeclarativeEngine *qmlEngine(const QObject *);
@@ -405,6 +410,34 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
return qmlAttachedPropertiesObject(&idx, obj, &T::staticMetaObject, create);
}
+inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor,
+ QScriptValue (*callback)(QDeclarativeEngine *, QScriptEngine *))
+{
+ QDeclarativePrivate::RegisterModuleApi api = {
+ 0,
+
+ uri, versionMajor, versionMinor,
+
+ callback, 0
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::ModuleApiRegistration, &api);
+}
+
+inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor,
+ QObject *(*callback)(QDeclarativeEngine *, QScriptEngine *))
+{
+ QDeclarativePrivate::RegisterModuleApi api = {
+ 0,
+
+ uri, versionMajor, versionMinor,
+
+ 0, callback
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::ModuleApiRegistration, &api);
+}
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QObject)
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp
index a5bd604c53..3e93ce7266 100644
--- a/src/declarative/qml/qdeclarativebinding.cpp
+++ b/src/declarative/qml/qdeclarativebinding.cpp
@@ -357,13 +357,17 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
} else {
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine);
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
bool isUndefined = false;
QVariant value;
QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
- if (wasDeleted)
+
+ if (wasDeleted) {
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
+ }
if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
@@ -420,8 +424,10 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
} else if (d->property.object() &&
!QDeclarativePropertyPrivate::write(d->property, value, flags)) {
- if (wasDeleted)
+ if (wasDeleted) {
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
+ }
QUrl url = QUrl(d->url);
int line = d->line;
@@ -440,14 +446,21 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
QLatin1String(QMetaType::typeName(d->property.propertyType())));
}
- if (wasDeleted)
+ if (wasDeleted) {
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
+ }
if (d->error.isValid()) {
if (!d->addError(ep)) ep->warning(this->error());
} else {
d->removeError();
}
+
+ // at this point, the binding has been evaluated. If any scarce
+ // resources were copied during the evaluation of the binding,
+ // we need to release those copies.
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
d->updating = false;
diff --git a/src/declarative/qml/qdeclarativecompiledbindings.cpp b/src/declarative/qml/qdeclarativecompiledbindings.cpp
deleted file mode 100644
index a6fcce4c99..0000000000
--- a/src/declarative/qml/qdeclarativecompiledbindings.cpp
+++ /dev/null
@@ -1,2906 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// #define COMPILEDBINDINGS_DEBUG
-// #define REGISTER_CLEANUP_DEBUG
-
-#include "private/qdeclarativecompiledbindings_p.h"
-
-#include <QtDeclarative/qdeclarativeinfo.h>
-#include <private/qdeclarativecontext_p.h>
-#include <private/qdeclarativejsast_p.h>
-#include <private/qdeclarativejsengine_p.h>
-#include <private/qdeclarativeexpression_p.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qnumeric.h>
-#include <private/qdeclarativeanchors_p_p.h>
-#include <private/qdeclarativeglobal_p.h>
-#include <private/qdeclarativefastproperties_p.h>
-#include <private/qdeclarativedebugtrace_p.h>
-
-QT_BEGIN_NAMESPACE
-
-DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL);
-DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER);
-DEFINE_BOOL_CONFIG_OPTION(qmlDisableFastProperties, QML_DISABLE_FAST_PROPERTIES);
-DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
-
-Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties);
-
-#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
-# define QML_THREADED_INTERPRETER
-#endif
-
-#define FOR_EACH_QML_INSTR(F) \
- F(Noop) /* Nop */ \
- F(BindingId) /* id */ \
- F(Subscribe) /* subscribe */ \
- F(SubscribeId) /* subscribe */ \
- F(FetchAndSubscribe) /* fetchAndSubscribe */ \
- F(LoadId) /* load */ \
- F(LoadScope) /* load */ \
- F(LoadRoot) /* load */ \
- F(LoadAttached) /* attached */ \
- F(ConvertIntToReal) /* unaryop */ \
- F(ConvertRealToInt) /* unaryop */ \
- F(Real) /* real_value */ \
- F(Int) /* int_value */ \
- F(Bool) /* bool_value */ \
- F(String) /* string_value */ \
- F(AddReal) /* binaryop */ \
- F(AddInt) /* binaryop */ \
- F(AddString) /* binaryop */ \
- F(MinusReal) /* binaryop */ \
- F(MinusInt) /* binaryop */ \
- F(CompareReal) /* binaryop */ \
- F(CompareString) /* binaryop */ \
- F(NotCompareReal) /* binaryop */ \
- F(NotCompareString) /* binaryop */ \
- F(GreaterThanReal) /* binaryop */ \
- F(MaxReal) /* binaryop */ \
- F(MinReal) /* binaryop */ \
- F(NewString) /* construct */ \
- F(NewUrl) /* construct */ \
- F(CleanupUrl) /* cleanup */ \
- F(CleanupString) /* cleanup */ \
- F(Copy) /* copy */ \
- F(Fetch) /* fetch */ \
- F(Store) /* store */ \
- F(Skip) /* skip */ \
- F(Done) /* done */ \
- /* Speculative property resolution */ \
- F(InitString) /* initstring */ \
- F(FindGeneric) /* find */ \
- F(FindGenericTerminal) /* find */ \
- F(FindProperty) /* find */ \
- F(FindPropertyTerminal) /* find */ \
- F(CleanupGeneric) /* cleanup */ \
- F(ConvertGenericToReal) /* unaryop */ \
- F(ConvertGenericToBool) /* unaryop */ \
- F(ConvertGenericToString) /* unaryop */ \
- F(ConvertGenericToUrl) /* unaryop */
-
-#define QML_INSTR_ENUM(I) I,
-#define QML_INSTR_ADDR(I) &&op_##I,
-
-#ifdef QML_THREADED_INTERPRETER
-# define QML_BEGIN_INSTR(I) op_##I:
-# define QML_END_INSTR(I) ++instr; goto *instr->common.code;
-# define QML_INSTR_HEADER void *code;
-#else
-# define QML_BEGIN_INSTR(I) case Instr::I:
-# define QML_END_INSTR(I) break;
-# define QML_INSTR_HEADER
-#endif
-
-
-using namespace QDeclarativeJS;
-
-namespace {
-// Supported types: int, qreal, QString (needs constr/destr), QObject*, bool
-struct Register {
- void setUndefined() { type = 0; }
- void setUnknownButDefined() { type = -1; }
- void setNaN() { setqreal(qSNaN()); }
- bool isUndefined() const { return type == 0; }
-
- void setQObject(QObject *o) { *((QObject **)data) = o; type = QMetaType::QObjectStar; }
- QObject *getQObject() const { return *((QObject **)data); }
-
- void setqreal(qreal v) { *((qreal *)data) = v; type = QMetaType::QReal; }
- qreal getqreal() const { return *((qreal *)data); }
-
- void setint(int v) { *((int *)data) = v; type = QMetaType::Int; }
- int getint() const { return *((int *)data); }
-
- void setbool(bool v) { *((bool *)data) = v; type = QMetaType::Bool; }
- bool getbool() const { return *((bool *)data); }
-
- QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
- QString *getstringptr() { return (QString *)typeDataPtr(); }
- QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
- const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
- const QString *getstringptr() const { return (QString *)typeDataPtr(); }
- const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
-
- void *typeDataPtr() { return (void *)&data; }
- void *typeMemory() { return (void *)data; }
- const void *typeDataPtr() const { return (void *)&data; }
- const void *typeMemory() const { return (void *)data; }
-
- int gettype() const { return type; }
- void settype(int t) { type = t; }
-
- int type; // Optional type
- void *data[2]; // Object stored here
-
-#ifdef REGISTER_CLEANUP_DEBUG
- Register() {
- type = 0;
- }
-
- ~Register() {
- int allowedTypes[] = { QMetaType::QObjectStar, QMetaType::QReal, QMetaType::Int, QMetaType::Bool, 0 };
- bool found = (type == 0);
- int *ctype = allowedTypes;
- while (!found && *ctype) {
- found = (*ctype == type);
- ++ctype;
- }
- if (!found)
- qWarning("Register leaked of type %d", type);
- }
-#endif
-};
-}
-
-class QDeclarativeCompiledBindingsPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QDeclarativeCompiledBindings)
-
-public:
- QDeclarativeCompiledBindingsPrivate();
- virtual ~QDeclarativeCompiledBindingsPrivate();
-
- struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
- Binding() : enabled(false), updating(0), property(0),
- scope(0), target(0), parent(0) {}
-
- // Inherited from QDeclarativeAbstractBinding
- virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
- virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
- virtual void destroy();
-
- int index:30;
- bool enabled:1;
- bool updating:1;
- int property;
- QObject *scope;
- QObject *target;
-
- QDeclarativeCompiledBindingsPrivate *parent;
- };
-
- typedef QDeclarativeNotifierEndpoint Subscription;
- Subscription *subscriptions;
- QScriptDeclarativeClass::PersistentIdentifier *identifiers;
-
- void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
-
- const char *programData;
- Binding *m_bindings;
- quint32 *m_signalTable;
-
- static int methodCount;
-
- void init();
- void run(int instr, QDeclarativeContextData *context,
- QDeclarativeDelayedError *error, QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags);
-
-
- inline void unsubscribe(int subIndex);
- inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
- inline void subscribe(QObject *o, int notifyIndex, int subIndex);
-
- QDeclarativePropertyCache::Data *findproperty(QObject *obj,
- const QScriptDeclarativeClass::Identifier &name,
- QDeclarativeEnginePrivate *enginePriv,
- QDeclarativePropertyCache::Data &local);
- bool findproperty(QObject *obj,
- Register *output,
- QDeclarativeEnginePrivate *enginePriv,
- int subIdx,
- const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal);
- void findgeneric(Register *output, // value output
- int subIdx, // Subscription index in config
- QDeclarativeContextData *context, // Context to search in
- const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal);
-};
-
-QDeclarativeCompiledBindingsPrivate::QDeclarativeCompiledBindingsPrivate()
-: subscriptions(0), identifiers(0)
-{
-}
-
-QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate()
-{
- delete [] subscriptions; subscriptions = 0;
- delete [] identifiers; identifiers = 0;
-}
-
-int QDeclarativeCompiledBindingsPrivate::methodCount = -1;
-
-QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context)
-: QObject(*(new QDeclarativeCompiledBindingsPrivate))
-{
- Q_D(QDeclarativeCompiledBindings);
-
- if (d->methodCount == -1)
- d->methodCount = QDeclarativeCompiledBindings::staticMetaObject.methodCount();
-
- d->programData = program;
-
- d->init();
-
- QDeclarativeAbstractExpression::setContext(context);
-}
-
-QDeclarativeCompiledBindings::~QDeclarativeCompiledBindings()
-{
- Q_D(QDeclarativeCompiledBindings);
-
- delete [] d->m_bindings;
-}
-
-QDeclarativeAbstractBinding *QDeclarativeCompiledBindings::configBinding(int index, QObject *target,
- QObject *scope, int property)
-{
- Q_D(QDeclarativeCompiledBindings);
-
- QDeclarativeCompiledBindingsPrivate::Binding *rv = d->m_bindings + index;
-
- rv->index = index;
- rv->property = property;
- rv->target = target;
- rv->scope = scope;
- rv->parent = d;
-
- addref(); // This is decremented in Binding::destroy()
-
- return rv;
-}
-
-void QDeclarativeCompiledBindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
-{
- if (enabled != e) {
- enabled = e;
-
- if (e) update(flags);
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
-{
- QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
- parent->run(this, flags);
- QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
-}
-
-void QDeclarativeCompiledBindingsPrivate::Binding::destroy()
-{
- enabled = false;
- removeFromObject();
- clear();
- parent->q_func()->release();
-}
-
-int QDeclarativeCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **)
-{
- Q_D(QDeclarativeCompiledBindings);
-
- if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
- id -= d->methodCount;
-
- quint32 *reeval = d->m_signalTable + d->m_signalTable[id];
- quint32 count = *reeval;
- ++reeval;
- for (quint32 ii = 0; ii < count; ++ii) {
- d->run(d->m_bindings + reeval[ii], QDeclarativePropertyPrivate::DontRemoveBinding);
- }
- }
- return -1;
-}
-
-void QDeclarativeCompiledBindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- if (!binding->enabled)
- return;
-
- QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
- if (!context || !context->isValid())
- return;
-
- if (binding->updating) {
- QString name;
- if (binding->property & 0xFFFF0000) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
-
- QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
- Q_ASSERT(vt);
-
- name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
- name.append(QLatin1String("."));
- name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
- } else {
- name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
- }
- qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeCompiledBindings", "Binding loop detected for property \"%1\"").arg(name);
- return;
- }
-
- binding->updating = true;
- if (binding->property & 0xFFFF0000) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
-
- QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
- Q_ASSERT(vt);
- vt->read(binding->target, binding->property & 0xFFFF);
-
- QObject *target = vt;
- run(binding->index, context, binding, binding->scope, target, flags);
-
- vt->write(binding->target, binding->property & 0xFFFF, flags);
- } else {
- run(binding->index, context, binding, binding->scope, binding->target, flags);
- }
- binding->updating = false;
-}
-
-namespace {
-// This structure is exactly 8-bytes in size
-struct Instr {
- enum {
- FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
- };
-
- union {
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing[7];
- } common;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing;
- quint16 column;
- quint32 line;
- } id;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing[3];
- quint16 subscriptions;
- quint16 identifiers;
- } init;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint16 offset;
- quint32 index;
- } subscribe;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- quint32 index;
- } load;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 reg;
- quint8 exceptionId;
- quint32 id;
- } attached;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 reg;
- quint8 exceptionId;
- quint32 index;
- } store;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 objectReg;
- quint8 exceptionId;
- quint16 subscription;
- quint16 function;
- } fetchAndSubscribe;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 objectReg;
- quint8 exceptionId;
- quint32 index;
- } fetch;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- qint8 src;
- quint8 packing[5];
- } copy;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[6];
- } construct;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- float value;
- } real_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- int value;
- } int_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- bool value;
- quint8 packing[5];
- } bool_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint16 length;
- quint32 offset;
- } string_value;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 src1;
- qint8 src2;
- quint8 packing[4];
- } binaryop;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 output;
- qint8 src;
- quint8 packing[5];
- } unaryop;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[2];
- quint32 count;
- } skip;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- qint8 src;
- quint8 exceptionId;
- quint16 name;
- quint16 subscribeIndex;
- } find;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- qint8 reg;
- quint8 packing[6];
- } cleanup;
- struct {
- QML_INSTR_HEADER
- quint8 type;
- quint8 packing[1];
- quint16 offset;
- quint32 dataIdx;
- } initstring;
- };
-};
-
-struct Program {
- quint32 bindings;
- quint32 dataLength;
- quint32 signalTableOffset;
- quint32 exceptionDataOffset;
- quint16 subscriptions;
- quint16 identifiers;
- quint16 instructionCount;
- quint16 compiled;
-
- const char *data() const { return ((const char *)this) + sizeof(Program); }
- const Instr *instructions() const { return (const Instr *)(data() + dataLength); }
-};
-}
-
-struct QDeclarativeBindingCompilerPrivate
-{
- struct Result {
- Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {}
- bool operator==(const Result &o) const {
- return unknownType == o.unknownType &&
- metaObject == o.metaObject &&
- type == o.type &&
- reg == o.reg;
- }
- bool operator!=(const Result &o) const {
- return !(*this == o);
- }
- bool unknownType;
- const QMetaObject *metaObject;
- int type;
- int reg;
-
- QSet<QString> subscriptionSet;
- };
-
- QDeclarativeBindingCompilerPrivate() : registers(0) {}
-
- void resetInstanceState();
- int commitCompile();
-
- QDeclarativeParser::Object *context;
- QDeclarativeParser::Object *component;
- QDeclarativeParser::Property *destination;
- QHash<QString, QDeclarativeParser::Object *> ids;
- QDeclarativeImports imports;
- QDeclarativeEnginePrivate *engine;
-
- QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)context, 16); }
-
- bool compile(QDeclarativeJS::AST::Node *);
-
- bool parseExpression(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryName(QDeclarativeJS::AST::Node *);
- bool parseName(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryArith(QDeclarativeJS::AST::Node *);
- bool parseArith(QDeclarativeJS::AST::Node *, Result &);
- bool numberArith(Result &, const Result &, const Result &, QSOperator::Op op);
- bool stringArith(Result &, const Result &, const Result &, QSOperator::Op op);
-
- bool tryLogic(QDeclarativeJS::AST::Node *);
- bool parseLogic(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryConditional(QDeclarativeJS::AST::Node *);
- bool parseConditional(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryConstant(QDeclarativeJS::AST::Node *);
- bool parseConstant(QDeclarativeJS::AST::Node *, Result &);
-
- bool tryMethod(QDeclarativeJS::AST::Node *);
- bool parseMethod(QDeclarativeJS::AST::Node *, Result &);
-
- bool buildName(QStringList &, QDeclarativeJS::AST::Node *, QList<QDeclarativeJS::AST::ExpressionNode *> *nodes = 0);
- bool fetch(Result &type, const QMetaObject *, int reg, int idx, const QStringList &, QDeclarativeJS::AST::ExpressionNode *);
-
- quint32 registers;
- QHash<int, QPair<int, int> > registerCleanups;
- int acquireReg(int cleanup = Instr::Noop, int cleanupType = 0);
- void registerCleanup(int reg, int cleanup, int cleanupType = 0);
- void releaseReg(int);
-
- int registerLiteralString(const QString &);
- int registerString(const QString &);
- QHash<QString, QPair<int, int> > registeredStrings;
- QByteArray data;
-
- bool subscription(const QStringList &, Result *);
- int subscriptionIndex(const QStringList &);
- bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs);
-
- quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *);
- QVector<quint64> exceptions;
-
- QSet<int> usedSubscriptionIds;
- QSet<QString> subscriptionSet;
- QHash<QString, int> subscriptionIds;
- QVector<Instr> bytecode;
-
- // Committed binding data
- struct {
- QList<int> offsets;
- QList<QSet<int> > dependencies;
-
- QVector<Instr> bytecode;
- QByteArray data;
- QHash<QString, int> subscriptionIds;
- QVector<quint64> exceptions;
-
- QHash<QString, QPair<int, int> > registeredStrings;
-
- int count() const { return offsets.count(); }
- } committed;
-
- QByteArray buildSignalTable() const;
- QByteArray buildExceptionData() const;
-};
-
-void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex)
-{
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
- sub->disconnect();
-}
-
-void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- unsubscribe(subIndex);
-
- if (p->idValues[idIndex]) {
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
- sub->target = q;
- sub->targetMethod = methodCount + subIndex;
- sub->connect(&p->idValues[idIndex].bindings);
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
- sub->target = q;
- sub->targetMethod = methodCount + subIndex;
- if (o)
- sub->connect(o, notifyIndex);
- else
- sub->disconnect();
-}
-
-// Conversion functions - these MUST match the QtScript expression path
-inline static qreal toReal(Register *reg, int type, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- if (type == QMetaType::QReal) {
- return reg->getqreal();
- } else if (type == qMetaTypeId<QVariant>()) {
- return reg->getvariantptr()->toReal();
- } else {
- if (ok) *ok = false;
- return 0;
- }
-}
-
-inline static QString toString(Register *reg, int type, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- if (type == QMetaType::QReal) {
- return QString::number(reg->getqreal());
- } else if (type == QMetaType::Int) {
- return QString::number(reg->getint());
- } else if (type == qMetaTypeId<QVariant>()) {
- return reg->getvariantptr()->toString();
- } else if (type == QMetaType::QString) {
- return *reg->getstringptr();
- } else {
- if (ok) *ok = false;
- return QString();
- }
-}
-
-inline static bool toBool(Register *reg, int type, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- if (type == QMetaType::Bool) {
- return reg->getbool();
- } else if (type == qMetaTypeId<QVariant>()) {
- return reg->getvariantptr()->toBool();
- } else {
- if (ok) *ok = false;
- return false;
- }
-}
-
-inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- QUrl base;
- if (type == qMetaTypeId<QVariant>()) {
- QVariant *var = reg->getvariantptr();
- int vt = var->type();
- if (vt == QVariant::Url) {
- base = var->toUrl();
- } else if (vt == QVariant::ByteArray) {
- base = QUrl(QString::fromUtf8(var->toByteArray()));
- } else if (vt == QVariant::String) {
- base = QUrl(var->toString());
- } else {
- if (ok) *ok = false;
- return QUrl();
- }
- } else if (type == QMetaType::QString) {
- base = QUrl(*reg->getstringptr());
- } else {
- if (ok) *ok = false;
- return QUrl();
- }
-
- if (!base.isEmpty() && base.isRelative())
- return context->url.resolved(base);
- else
- return base;
-}
-
-static QObject *variantToQObject(const QVariant &value, bool *ok)
-{
- if (ok) *ok = true;
-
- if (value.userType() == QMetaType::QObjectStar) {
- return qvariant_cast<QObject*>(value);
- } else {
- if (ok) *ok = false;
- return 0;
- }
-}
-
-bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *output,
- QDeclarativeEnginePrivate *enginePriv,
- int subIdx, const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal)
-{
- if (!obj) {
- output->setUndefined();
- return false;
- }
-
- QDeclarativePropertyCache::Data local;
- QDeclarativePropertyCache::Data *property =
- QDeclarativePropertyCache::property(QDeclarativeEnginePrivate::get(enginePriv), obj, name, local);
-
- if (property) {
- if (subIdx != -1)
- subscribe(obj, property->notifyIndex, subIdx);
-
- if (property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::QObjectStar);
- } else if (property->propType == qMetaTypeId<QVariant>()) {
- QVariant v;
- void *args[] = { &v, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
-
- if (isTerminal) {
- new (output->typeDataPtr()) QVariant(v);
- output->settype(qMetaTypeId<QVariant>());
- } else {
- bool ok;
- output->setQObject(variantToQObject(v, &ok));
- if (!ok)
- output->setUndefined();
- else
- output->settype(QMetaType::QObjectStar);
- }
-
- } else {
- if (!isTerminal) {
- output->setUndefined();
- } else if (property->propType == QMetaType::QReal) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::QReal);
- } else if (property->propType == QMetaType::Int) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::Int);
- } else if (property->propType == QMetaType::Bool) {
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::Bool);
- } else if (property->propType == QMetaType::QString) {
- new (output->typeDataPtr()) QString();
- void *args[] = { output->typeDataPtr(), 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
- output->settype(QMetaType::QString);
- } else {
- new (output->typeDataPtr())
- QVariant(obj->metaObject()->property(property->coreIndex).read(obj));
- output->settype(qMetaTypeId<QVariant>());
- }
- }
-
- return true;
- } else {
- output->setUndefined();
- return false;
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output,
- int subIdx,
- QDeclarativeContextData *context,
- const QScriptDeclarativeClass::Identifier &name,
- bool isTerminal)
-{
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context->engine);
-
- while (context) {
-
- int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1;
-
-
- if (contextPropertyIndex != -1) {
-
- if (contextPropertyIndex < context->idValueCount) {
- output->setQObject(context->idValues[contextPropertyIndex]);
- output->settype(QMetaType::QObjectStar);
-
- if (subIdx != -1)
- subscribeId(context, contextPropertyIndex, subIdx);
-
- } else {
- QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
- const QVariant &value = cp->propertyValues.at(contextPropertyIndex);
-
- if (isTerminal) {
- new (output->typeDataPtr()) QVariant(value);
- output->settype(qMetaTypeId<QVariant>());
- } else {
- bool ok;
- output->setQObject(variantToQObject(value, &ok));
- if (!ok) { output->setUndefined(); }
- else { output->settype(QMetaType::QObjectStar); }
- return;
- }
-
- if (subIdx != -1)
- subscribe(context->asQDeclarativeContext(), contextPropertyIndex + cp->notifyIndex, subIdx);
-
-
- }
-
- return;
- }
-
- if (QObject *root = context->contextObject) {
-
- if (findproperty(root, output, enginePriv, subIdx, name, isTerminal))
- return;
-
- }
-
- context = context->parent;
- }
-
- output->setUndefined();
-}
-
-void QDeclarativeCompiledBindingsPrivate::init()
-{
- Program *program = (Program *)programData;
- if (program->subscriptions)
- subscriptions = new QDeclarativeCompiledBindingsPrivate::Subscription[program->subscriptions];
- if (program->identifiers)
- identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
-
- m_signalTable = (quint32 *)(program->data() + program->signalTableOffset);
- m_bindings = new QDeclarativeCompiledBindingsPrivate::Binding[program->bindings];
-}
-
-static void throwException(int id, QDeclarativeDelayedError *error,
- Program *program, QDeclarativeContextData *context,
- const QString &description = QString())
-{
- error->error.setUrl(context->url);
- if (description.isEmpty())
- error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
- else
- error->error.setDescription(description);
- if (id != 0xFF) {
- quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id);
- error->error.setLine((e >> 32) & 0xFFFFFFFF);
- error->error.setColumn(e & 0xFFFFFFFF);
- } else {
- error->error.setLine(-1);
- error->error.setColumn(-1);
- }
- if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
- QDeclarativeEnginePrivate::warning(context->engine, error->error);
-}
-
-static void dumpInstruction(const Instr *instr)
-{
- switch (instr->common.type) {
- case Instr::Noop:
- qWarning().nospace() << "\t" << "Noop";
- break;
- case Instr::BindingId:
- qWarning().nospace() << instr->id.line << ":" << instr->id.column << ":";
- break;
- case Instr::Subscribe:
- qWarning().nospace() << "\t" << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
- break;
- case Instr::SubscribeId:
- qWarning().nospace() << "\t" << "SubscribeId" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
- break;
- case Instr::FetchAndSubscribe:
- qWarning().nospace() << "\t" << "FetchAndSubscribe" << "\t" << instr->fetchAndSubscribe.output << "\t" << instr->fetchAndSubscribe.objectReg << "\t" << instr->fetchAndSubscribe.subscription;
- break;
- case Instr::LoadId:
- qWarning().nospace() << "\t" << "LoadId" << "\t\t\t" << instr->load.index << "\t" << instr->load.reg;
- break;
- case Instr::LoadScope:
- qWarning().nospace() << "\t" << "LoadScope" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
- break;
- case Instr::LoadRoot:
- qWarning().nospace() << "\t" << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
- break;
- case Instr::LoadAttached:
- qWarning().nospace() << "\t" << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.id;
- break;
- case Instr::ConvertIntToReal:
- qWarning().nospace() << "\t" << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertRealToInt:
- qWarning().nospace() << "\t" << "ConvertRealToInt" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::Real:
- qWarning().nospace() << "\t" << "Real" << "\t\t\t" << instr->real_value.reg << "\t" << instr->real_value.value;
- break;
- case Instr::Int:
- qWarning().nospace() << "\t" << "Int" << "\t\t\t" << instr->int_value.reg << "\t" << instr->int_value.value;
- break;
- case Instr::Bool:
- qWarning().nospace() << "\t" << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value;
- break;
- case Instr::String:
- qWarning().nospace() << "\t" << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length;
- break;
- case Instr::AddReal:
- qWarning().nospace() << "\t" << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::AddInt:
- qWarning().nospace() << "\t" << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::AddString:
- qWarning().nospace() << "\t" << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MinusReal:
- qWarning().nospace() << "\t" << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MinusInt:
- qWarning().nospace() << "\t" << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::CompareReal:
- qWarning().nospace() << "\t" << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::CompareString:
- qWarning().nospace() << "\t" << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::NotCompareReal:
- qWarning().nospace() << "\t" << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::NotCompareString:
- qWarning().nospace() << "\t" << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::GreaterThanReal:
- qWarning().nospace() << "\t" << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MaxReal:
- qWarning().nospace() << "\t" << "MaxReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::MinReal:
- qWarning().nospace() << "\t" << "MinReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
- break;
- case Instr::NewString:
- qWarning().nospace() << "\t" << "NewString" << "\t\t" << instr->construct.reg;
- break;
- case Instr::NewUrl:
- qWarning().nospace() << "\t" << "NewUrl" << "\t\t\t" << instr->construct.reg;
- break;
- case Instr::CleanupString:
- qWarning().nospace() << "\t" << "CleanupString" << "\t\t" << instr->cleanup.reg;
- break;
- case Instr::CleanupUrl:
- qWarning().nospace() << "\t" << "CleanupUrl" << "\t\t" << instr->cleanup.reg;
- break;
- case Instr::Fetch:
- qWarning().nospace() << "\t" << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg;
- break;
- case Instr::Store:
- qWarning().nospace() << "\t" << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg;
- break;
- case Instr::Copy:
- qWarning().nospace() << "\t" << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src;
- break;
- case Instr::Skip:
- qWarning().nospace() << "\t" << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count;
- break;
- case Instr::Done:
- qWarning().nospace() << "\t" << "Done";
- break;
- case Instr::InitString:
- qWarning().nospace() << "\t" << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx;
- break;
- case Instr::FindGeneric:
- qWarning().nospace() << "\t" << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name;
- break;
- case Instr::FindGenericTerminal:
- qWarning().nospace() << "\t" << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" << instr->find.name;
- break;
- case Instr::FindProperty:
- qWarning().nospace() << "\t" << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
- break;
- case Instr::FindPropertyTerminal:
- qWarning().nospace() << "\t" << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
- break;
- case Instr::CleanupGeneric:
- qWarning().nospace() << "\t" << "CleanupGeneric" << "\t\t" << instr->cleanup.reg;
- break;
- case Instr::ConvertGenericToReal:
- qWarning().nospace() << "\t" << "ConvertGenericToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertGenericToBool:
- qWarning().nospace() << "\t" << "ConvertGenericToBool" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertGenericToString:
- qWarning().nospace() << "\t" << "ConvertGenericToString" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- case Instr::ConvertGenericToUrl:
- qWarning().nospace() << "\t" << "ConvertGenericToUrl" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
- break;
- default:
- qWarning().nospace() << "\t" << "Unknown";
- break;
- }
-}
-
-void QDeclarativeCompiledBindingsPrivate::run(int instrIndex,
- QDeclarativeContextData *context, QDeclarativeDelayedError *error,
- QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags)
-{
- Q_Q(QDeclarativeCompiledBindings);
-
- error->removeError();
-
- Register registers[32];
-
- QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
- Program *program = (Program *)programData;
- const Instr *instr = program->instructions();
- instr += instrIndex;
- const char *data = program->data();
-
-#ifdef QML_THREADED_INTERPRETER
- static void *decode_instr[] = {
- FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
- };
-
- if (!program->compiled) {
- program->compiled = true;
- const Instr *inop = program->instructions();
- for (int i = 0; i < program->instructionCount; ++i) {
- Instr *op = (Instr *) inop++;
- op->common.code = decode_instr[op->common.type];
- }
- }
-
- goto *instr->common.code;
-#else
- // return;
-
-#ifdef COMPILEDBINDINGS_DEBUG
- qWarning().nospace() << "Begin binding run";
-#endif
-
- while (instr) {
- switch (instr->common.type) {
-
-#ifdef COMPILEDBINDINGS_DEBUG
- dumpInstruction(instr);
-#endif
-
-#endif
-
- QML_BEGIN_INSTR(Noop)
- QML_END_INSTR(Noop)
-
- QML_BEGIN_INSTR(BindingId)
- QML_END_INSTR(BindingId)
-
- QML_BEGIN_INSTR(SubscribeId)
- subscribeId(context, instr->subscribe.index, instr->subscribe.offset);
- QML_END_INSTR(SubscribeId)
-
- QML_BEGIN_INSTR(Subscribe)
- {
- QObject *o = 0;
- const Register &object = registers[instr->subscribe.reg];
- if (!object.isUndefined()) o = object.getQObject();
- subscribe(o, instr->subscribe.index, instr->subscribe.offset);
- }
- QML_END_INSTR(Subscribe)
-
- QML_BEGIN_INSTR(FetchAndSubscribe)
- {
- const Register &input = registers[instr->fetchAndSubscribe.objectReg];
- Register &output = registers[instr->fetchAndSubscribe.output];
-
- if (input.isUndefined()) {
- throwException(instr->fetchAndSubscribe.exceptionId, error, program, context);
- return;
- }
-
- QObject *object = input.getQObject();
- if (!object) {
- output.setUndefined();
- } else {
- int subIdx = instr->fetchAndSubscribe.subscription;
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = 0;
- if (subIdx != -1) {
- sub = (subscriptions + subIdx);
- sub->target = q;
- sub->targetMethod = methodCount + subIdx;
- }
- fastProperties()->accessor(instr->fetchAndSubscribe.function)(object, output.typeDataPtr(), sub);
- }
- }
- QML_END_INSTR(FetchAndSubscribe)
-
- QML_BEGIN_INSTR(LoadId)
- registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
- QML_END_INSTR(LoadId)
-
- QML_BEGIN_INSTR(LoadScope)
- registers[instr->load.reg].setQObject(scope);
- QML_END_INSTR(LoadScope)
-
- QML_BEGIN_INSTR(LoadRoot)
- registers[instr->load.reg].setQObject(context->contextObject);
- QML_END_INSTR(LoadRoot)
-
- QML_BEGIN_INSTR(LoadAttached)
- {
- const Register &input = registers[instr->attached.reg];
- Register &output = registers[instr->attached.output];
- if (input.isUndefined()) {
- throwException(instr->attached.exceptionId, error, program, context);
- return;
- }
-
- QObject *object = registers[instr->attached.reg].getQObject();
- if (!object) {
- output.setUndefined();
- } else {
- QObject *attached =
- qmlAttachedPropertiesObjectById(instr->attached.id,
- registers[instr->attached.reg].getQObject(),
- true);
- Q_ASSERT(attached);
- output.setQObject(attached);
- }
- }
- QML_END_INSTR(LoadAttached)
-
- QML_BEGIN_INSTR(ConvertIntToReal)
- {
- const Register &input = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (input.isUndefined()) output.setUndefined();
- else output.setqreal(qreal(input.getint()));
- }
- QML_END_INSTR(ConvertIntToReal)
-
- QML_BEGIN_INSTR(ConvertRealToInt)
- {
- const Register &input = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (input.isUndefined()) output.setUndefined();
- else output.setint(qRound(input.getqreal()));
- }
- QML_END_INSTR(ConvertRealToInt)
-
- QML_BEGIN_INSTR(Real)
- registers[instr->real_value.reg].setqreal(instr->real_value.value);
- QML_END_INSTR(Real)
-
- QML_BEGIN_INSTR(Int)
- registers[instr->int_value.reg].setint(instr->int_value.value);
- QML_END_INSTR(Int)
-
- QML_BEGIN_INSTR(Bool)
- registers[instr->bool_value.reg].setbool(instr->bool_value.value);
- QML_END_INSTR(Bool)
-
- QML_BEGIN_INSTR(String)
- {
- Register &output = registers[instr->string_value.reg];
- new (output.getstringptr())
- QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
- output.settype(QMetaType::QString);
- }
- QML_END_INSTR(String)
-
- QML_BEGIN_INSTR(AddReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(lhs.getqreal() + rhs.getqreal());
- }
- QML_END_INSTR(AddReal)
-
- QML_BEGIN_INSTR(AddInt)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setint(lhs.getint() + rhs.getint());
- }
- QML_END_INSTR(AddInt)
-
- QML_BEGIN_INSTR(AddString)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() && rhs.isUndefined()) { output.setNaN(); }
- else {
- if (lhs.isUndefined())
- new (output.getstringptr())
- QString(QLatin1String("undefined") + *registers[instr->binaryop.src2].getstringptr());
- else if (rhs.isUndefined())
- new (output.getstringptr())
- QString(*registers[instr->binaryop.src1].getstringptr() + QLatin1String("undefined"));
- else
- new (output.getstringptr())
- QString(*registers[instr->binaryop.src1].getstringptr() +
- *registers[instr->binaryop.src2].getstringptr());
- output.settype(QMetaType::QString);
- }
- }
- QML_END_INSTR(AddString)
-
- QML_BEGIN_INSTR(MinusReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(lhs.getqreal() - rhs.getqreal());
- }
- QML_END_INSTR(MinusReal)
-
- QML_BEGIN_INSTR(MinusInt)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setint(lhs.getint() - rhs.getint());
- }
- QML_END_INSTR(MinusInt)
-
- QML_BEGIN_INSTR(CompareReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
- else output.setbool(lhs.getqreal() == rhs.getqreal());
- }
- QML_END_INSTR(CompareReal)
-
- QML_BEGIN_INSTR(CompareString)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
- else output.setbool(*lhs.getstringptr() == *rhs.getstringptr());
- }
- QML_END_INSTR(CompareString)
-
- QML_BEGIN_INSTR(NotCompareReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
- else output.setbool(lhs.getqreal() != rhs.getqreal());
- }
- QML_END_INSTR(NotCompareReal)
-
- QML_BEGIN_INSTR(NotCompareString)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
- else output.setbool(*lhs.getstringptr() != *rhs.getstringptr());
- }
- QML_END_INSTR(NotCompareString)
-
- QML_BEGIN_INSTR(GreaterThanReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(false);
- else output.setbool(lhs.getqreal() > rhs.getqreal());
- }
- QML_END_INSTR(GreaterThanReal)
-
- QML_BEGIN_INSTR(MaxReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(qMax(lhs.getqreal(), rhs.getqreal()));
- }
- QML_END_INSTR(MaxReal)
-
- QML_BEGIN_INSTR(MinReal)
- {
- const Register &lhs = registers[instr->binaryop.src1];
- const Register &rhs = registers[instr->binaryop.src2];
- Register &output = registers[instr->binaryop.output];
- if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
- else output.setqreal(qMin(lhs.getqreal(), rhs.getqreal()));
- }
- QML_END_INSTR(MinReal)
-
- QML_BEGIN_INSTR(NewString)
- {
- Register &output = registers[instr->construct.reg];
- new (output.getstringptr()) QString;
- output.settype(QMetaType::QString);
- }
- QML_END_INSTR(NewString)
-
- QML_BEGIN_INSTR(NewUrl)
- {
- Register &output = registers[instr->construct.reg];
- new (output.geturlptr()) QUrl;
- output.settype(QMetaType::QUrl);
- }
- QML_END_INSTR(NewUrl)
-
- QML_BEGIN_INSTR(CleanupString)
- registers[instr->cleanup.reg].getstringptr()->~QString();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- QML_END_INSTR(CleanupString)
-
- QML_BEGIN_INSTR(CleanupUrl)
- registers[instr->cleanup.reg].geturlptr()->~QUrl();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- QML_END_INSTR(CleanupUrl)
-
- QML_BEGIN_INSTR(Fetch)
- {
- const Register &input = registers[instr->fetch.objectReg];
- Register &output = registers[instr->fetch.output];
-
- if (input.isUndefined()) {
- throwException(instr->fetch.exceptionId, error, program, context);
- return;
- }
-
- QObject *object = input.getQObject();
- if (!object) {
- output.setUndefined();
- } else {
- void *argv[] = { output.typeDataPtr(), 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
- }
- }
- QML_END_INSTR(Fetch)
-
- QML_BEGIN_INSTR(Store)
- {
- Register &data = registers[instr->store.reg];
- if (data.isUndefined()) {
- throwException(instr->store.exceptionId, error, program, context,
- QLatin1String("Unable to assign undefined value"));
- return;
- }
-
- int status = -1;
- void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
- QMetaObject::metacall(output, QMetaObject::WriteProperty,
- instr->store.index, argv);
- }
- QML_END_INSTR(Store)
-
- QML_BEGIN_INSTR(Copy)
- registers[instr->copy.reg] = registers[instr->copy.src];
- QML_END_INSTR(Copy)
-
- QML_BEGIN_INSTR(Skip)
- if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool())
- instr += instr->skip.count;
- QML_END_INSTR(Skip)
-
- QML_BEGIN_INSTR(Done)
- return;
- QML_END_INSTR(Done)
-
- QML_BEGIN_INSTR(InitString)
- if (!identifiers[instr->initstring.offset].identifier) {
- quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
- QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
-
- QString str = QString::fromRawData(strdata, len);
-
- identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
- }
- QML_END_INSTR(InitString)
-
- QML_BEGIN_INSTR(FindGenericTerminal)
- // We start the search in the parent context, as we know that the
- // name is not present in the current context or it would have been
- // found during the static compile
- findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
- context->parent,
- identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindGenericTerminal);
- QML_END_INSTR(FindGenericTerminal)
-
- QML_BEGIN_INSTR(FindGeneric)
- // We start the search in the parent context, as we know that the
- // name is not present in the current context or it would have been
- // found during the static compile
- findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
- context->parent,
- identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindGenericTerminal);
- QML_END_INSTR(FindGeneric)
-
- QML_BEGIN_INSTR(FindPropertyTerminal)
- {
- const Register &object = registers[instr->find.src];
- if (object.isUndefined()) {
- throwException(instr->find.exceptionId, error, program, context);
- return;
- }
-
- findproperty(object.getQObject(), registers + instr->find.reg,
- QDeclarativeEnginePrivate::get(context->engine),
- instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindPropertyTerminal);
- }
- QML_END_INSTR(FindPropertyTerminal)
-
- QML_BEGIN_INSTR(FindProperty)
- {
- const Register &object = registers[instr->find.src];
- if (object.isUndefined()) {
- throwException(instr->find.exceptionId, error, program, context);
- return;
- }
-
- findproperty(object.getQObject(), registers + instr->find.reg,
- QDeclarativeEnginePrivate::get(context->engine),
- instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
- instr->common.type == Instr::FindPropertyTerminal);
- }
- QML_END_INSTR(FindProperty)
-
- QML_BEGIN_INSTR(CleanupGeneric)
- {
- int type = registers[instr->cleanup.reg].gettype();
- if (type == qMetaTypeId<QVariant>()) {
- registers[instr->cleanup.reg].getvariantptr()->~QVariant();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- } else if (type == QMetaType::QString) {
- registers[instr->cleanup.reg].getstringptr()->~QString();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- } else if (type == QMetaType::QUrl) {
- registers[instr->cleanup.reg].geturlptr()->~QUrl();
-#ifdef REGISTER_CLEANUP_DEBUG
- registers[instr->cleanup.reg].setUndefined();
-#endif
- }
- }
- QML_END_INSTR(CleanupGeneric)
-
- QML_BEGIN_INSTR(ConvertGenericToReal)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- output.setqreal(toReal(&input, input.gettype(), &ok));
- if (!ok) output.setUndefined();
- }
- QML_END_INSTR(ConvertGenericToReal)
-
- QML_BEGIN_INSTR(ConvertGenericToBool)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- output.setbool(toBool(&input, input.gettype(), &ok));
- if (!ok) output.setUndefined();
- }
- QML_END_INSTR(ConvertGenericToBool)
-
- QML_BEGIN_INSTR(ConvertGenericToString)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- QString str = toString(&input, input.gettype(), &ok);
- if (ok) { new (output.getstringptr()) QString(str); output.settype(QMetaType::QString); }
- else { output.setUndefined(); }
- }
- QML_END_INSTR(ConvertGenericToString)
-
- QML_BEGIN_INSTR(ConvertGenericToUrl)
- {
- Register &output = registers[instr->unaryop.output];
- Register &input = registers[instr->unaryop.src];
- bool ok = true;
- QUrl url = toUrl(&input, input.gettype(), context, &ok);
- if (ok) { new (output.geturlptr()) QUrl(url); output.settype(QMetaType::QUrl); }
- else { output.setUndefined(); }
- }
- QML_END_INSTR(ConvertGenericToUrl)
-
-#ifdef QML_THREADED_INTERPRETER
- // nothing to do
-#else
- default:
- qFatal("EEK");
- break;
- } // switch
-
- ++instr;
- } // while
-#endif
-}
-
-void QDeclarativeBindingCompiler::dump(const QByteArray &programData)
-{
- const Program *program = (const Program *)programData.constData();
-
- qWarning() << "Program.bindings:" << program->bindings;
- qWarning() << "Program.dataLength:" << program->dataLength;
- qWarning() << "Program.subscriptions:" << program->subscriptions;
- qWarning() << "Program.indentifiers:" << program->identifiers;
-
- int count = program->instructionCount;
- const Instr *instr = program->instructions();
-
- while (count--) {
-
- dumpInstruction(instr);
- ++instr;
- }
-}
-
-/*!
-Clear the state associated with attempting to compile a specific binding.
-This does not clear the global "committed binding" states.
-*/
-void QDeclarativeBindingCompilerPrivate::resetInstanceState()
-{
- registers = 0;
- registerCleanups.clear();
- data = committed.data;
- exceptions = committed.exceptions;
- usedSubscriptionIds.clear();
- subscriptionSet.clear();
- subscriptionIds = committed.subscriptionIds;
- registeredStrings = committed.registeredStrings;
- bytecode.clear();
-}
-
-/*!
-Mark the last compile as successful, and add it to the "committed data"
-section.
-
-Returns the index for the committed binding.
-*/
-int QDeclarativeBindingCompilerPrivate::commitCompile()
-{
- int rv = committed.count();
- committed.offsets << committed.bytecode.count();
- committed.dependencies << usedSubscriptionIds;
- committed.bytecode << bytecode;
- committed.data = data;
- committed.exceptions = exceptions;
- committed.subscriptionIds = subscriptionIds;
- committed.registeredStrings = registeredStrings;
- return rv;
-}
-
-bool QDeclarativeBindingCompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
-{
- resetInstanceState();
-
- if (destination->type == -1)
- return false;
-
- if (bindingsDump()) {
- QDeclarativeJS::AST::ExpressionNode *n = node->expressionCast();
- if (n) {
- Instr id;
- id.common.type = Instr::BindingId;
- id.id.column = n->firstSourceLocation().startColumn;
- id.id.line = n->firstSourceLocation().startLine;
- bytecode << id;
- }
- }
-
- Result type;
-
- if (!parseExpression(node, type))
- return false;
-
- if (subscriptionSet.count() > 0xFFFF ||
- registeredStrings.count() > 0xFFFF)
- return false;
-
- if (type.unknownType) {
- if (!qmlExperimental())
- return false;
-
- if (destination->type != QMetaType::QReal &&
- destination->type != QVariant::String &&
- destination->type != QMetaType::Bool &&
- destination->type != QVariant::Url)
- return false;
-
- int convertReg = acquireReg();
- if (convertReg == -1)
- return false;
-
- if (destination->type == QMetaType::QReal) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToReal;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- } else if (destination->type == QVariant::String) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToString;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- } else if (destination->type == QMetaType::Bool) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToBool;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- } else if (destination->type == QVariant::Url) {
- Instr convert;
- convert.common.type = Instr::ConvertGenericToUrl;
- convert.unaryop.output = convertReg;
- convert.unaryop.src = type.reg;
- bytecode << convert;
- }
-
- Instr cleanup;
- cleanup.common.type = Instr::CleanupGeneric;
- cleanup.cleanup.reg = type.reg;
- bytecode << cleanup;
-
- Instr instr;
- instr.common.type = Instr::Store;
- instr.store.output = 0;
- instr.store.index = destination->index;
- instr.store.reg = convertReg;
- instr.store.exceptionId = exceptionId(node->expressionCast());
- bytecode << instr;
-
- if (destination->type == QVariant::String) {
- Instr cleanup;
- cleanup.common.type = Instr::CleanupString;
- cleanup.cleanup.reg = convertReg;
- bytecode << cleanup;
- } else if (destination->type == QVariant::Url) {
- Instr cleanup;
- cleanup.common.type = Instr::CleanupUrl;
- cleanup.cleanup.reg = convertReg;
- bytecode << cleanup;
- }
-
- releaseReg(convertReg);
-
- Instr done;
- done.common.type = Instr::Done;
- bytecode << done;
-
- } else {
- // Can we store the final value?
- if (type.type == QVariant::Int &&
- destination->type == QMetaType::QReal) {
- Instr instr;
- instr.common.type = Instr::ConvertIntToReal;
- instr.unaryop.output = type.reg;
- instr.unaryop.src = type.reg;
- bytecode << instr;
- type.type = QMetaType::QReal;
- } else if (type.type == QMetaType::QReal &&
- destination->type == QVariant::Int) {
- Instr instr;
- instr.common.type = Instr::ConvertRealToInt;
- instr.unaryop.output = type.reg;
- instr.unaryop.src = type.reg;
- bytecode << instr;
- type.type = QVariant::Int;
- } else if (type.type == destination->type) {
- } else {
- const QMetaObject *from = type.metaObject;
- const QMetaObject *to = engine->rawMetaObjectForType(destination->type);
-
- if (QDeclarativePropertyPrivate::canConvert(from, to))
- type.type = destination->type;
- }
-
- if (type.type == destination->type) {
- Instr instr;
- instr.common.type = Instr::Store;
- instr.store.output = 0;
- instr.store.index = destination->index;
- instr.store.reg = type.reg;
- instr.store.exceptionId = exceptionId(node->expressionCast());
- bytecode << instr;
-
- releaseReg(type.reg);
-
- Instr done;
- done.common.type = Instr::Done;
- bytecode << done;
- } else {
- return false;
- }
- }
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseExpression(QDeclarativeJS::AST::Node *node, Result &type)
-{
- while (node->kind == AST::Node::Kind_NestedExpression)
- node = static_cast<AST::NestedExpression *>(node)->expression;
-
- if (tryArith(node)) {
- if (!parseArith(node, type)) return false;
- } else if (tryLogic(node)) {
- if (!parseLogic(node, type)) return false;
- } else if (tryConditional(node)) {
- if (!parseConditional(node, type)) return false;
- } else if (tryName(node)) {
- if (!parseName(node, type)) return false;
- } else if (tryConstant(node)) {
- if (!parseConstant(node, type)) return false;
- } else if (tryMethod(node)) {
- if (!parseMethod(node, type)) return false;
- } else {
- return false;
- }
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryName(QDeclarativeJS::AST::Node *node)
-{
- return node->kind == AST::Node::Kind_IdentifierExpression ||
- node->kind == AST::Node::Kind_FieldMemberExpression;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseName(AST::Node *node, Result &type)
-{
- QStringList nameParts;
- QList<AST::ExpressionNode *> nameNodes;
- if (!buildName(nameParts, node, &nameNodes))
- return false;
-
- int reg = acquireReg();
- if (reg == -1)
- return false;
- type.reg = reg;
-
- QDeclarativeParser::Object *absType = 0;
-
- QStringList subscribeName;
-
- bool wasAttachedObject = false;
-
- for (int ii = 0; ii < nameParts.count(); ++ii) {
- const QString &name = nameParts.at(ii);
-
- // We don't handle signal properties or attached properties
- if (name.length() > 2 && name.startsWith(QLatin1String("on")) &&
- name.at(2).isUpper())
- return false;
-
- QDeclarativeType *attachType = 0;
- if (name.at(0).isUpper()) {
- // Could be an attached property
- if (ii == nameParts.count() - 1)
- return false;
- if (nameParts.at(ii + 1).at(0).isUpper())
- return false;
-
- QDeclarativeImportedNamespace *ns = 0;
- if (!imports.resolveType(name.toUtf8(), &attachType, 0, 0, 0, &ns))
- return false;
- if (ns || !attachType || !attachType->attachedPropertiesType())
- return false;
-
- wasAttachedObject = true;
- }
-
- if (ii == 0) {
-
- if (attachType) {
- Instr instr;
- instr.common.type = Instr::LoadScope;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
-
- Instr attach;
- attach.common.type = Instr::LoadAttached;
- attach.attached.output = reg;
- attach.attached.reg = reg;
- attach.attached.id = attachType->attachedPropertiesId();
- attach.attached.exceptionId = exceptionId(nameNodes.at(ii));
- bytecode << attach;
-
- subscribeName << contextName();
- subscribeName << QLatin1String("$$$ATTACH_") + name;
-
- absType = 0;
- type.metaObject = attachType->attachedPropertiesType();
-
- continue;
- } else if (ids.contains(name)) {
- QDeclarativeParser::Object *idObject = ids.value(name);
- absType = idObject;
- type.metaObject = absType->metaObject();
-
- // We check if the id object is the root or
- // scope object to avoid a subscription
- if (idObject == component) {
- Instr instr;
- instr.common.type = Instr::LoadRoot;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
- } else if (idObject == context) {
- Instr instr;
- instr.common.type = Instr::LoadScope;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
- } else {
- Instr instr;
- instr.common.type = Instr::LoadId;
- instr.load.index = idObject->idIndex;
- instr.load.reg = reg;
- bytecode << instr;
-
- subscribeName << QLatin1String("$$$ID_") + name;
-
- if (subscription(subscribeName, &type)) {
- Instr sub;
- sub.common.type = Instr::SubscribeId;
- sub.subscribe.offset = subscriptionIndex(subscribeName);
- sub.subscribe.reg = reg;
- sub.subscribe.index = instr.load.index;
- bytecode << sub;
- }
- }
-
- } else {
-
- QByteArray utf8Name = name.toUtf8();
- const char *cname = utf8Name.constData();
-
- int d0Idx = (context == component)?-1:context->metaObject()->indexOfProperty(cname);
- int d1Idx = -1;
- if (d0Idx == -1)
- d1Idx = component->metaObject()->indexOfProperty(cname);
-
- if (d0Idx != -1) {
- Instr instr;
- instr.common.type = Instr::LoadScope;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
-
- subscribeName << contextName();
- subscribeName << name;
-
- if (!fetch(type, context->metaObject(), reg, d0Idx, subscribeName, nameNodes.at(ii)))
- return false;
- } else if(d1Idx != -1) {
- Instr instr;
- instr.common.type = Instr::LoadRoot;
- instr.load.index = 0;
- instr.load.reg = reg;
- bytecode << instr;
-
- subscribeName << QLatin1String("$$$ROOT");
- subscribeName << name;
-
- if (!fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii)))
- return false;
- } else if (qmlExperimental()) {
- Instr find;
- if (nameParts.count() == 1)
- find.common.type = Instr::FindGenericTerminal;
- else
- find.common.type = Instr::FindGeneric;
-
- find.find.reg = reg;
- find.find.src = -1;
- find.find.name = registerString(name);
- find.find.exceptionId = exceptionId(nameNodes.at(ii));
-
- subscribeName << QString(QLatin1String("$$$Generic_") + name);
- if (subscription(subscribeName, &type))
- find.find.subscribeIndex = subscriptionIndex(subscribeName);
- else
- find.find.subscribeIndex = -1;
-
- bytecode << find;
- type.unknownType = true;
- }
-
- if (!type.unknownType && type.type == -1)
- return false; // Couldn't fetch that type
- }
-
- } else {
-
- if (attachType) {
- Instr attach;
- attach.common.type = Instr::LoadAttached;
- attach.attached.output = reg;
- attach.attached.reg = reg;
- attach.attached.id = attachType->attachedPropertiesId();
- bytecode << attach;
-
- absType = 0;
- type.metaObject = attachType->attachedPropertiesType();
-
- subscribeName << QLatin1String("$$$ATTACH_") + name;
- continue;
- }
-
- const QMetaObject *mo = 0;
- if (absType)
- mo = absType->metaObject();
- else if (type.metaObject)
- mo = type.metaObject;
-
- QByteArray utf8Name = name.toUtf8();
- const char *cname = utf8Name.constData();
- int idx = mo?mo->indexOfProperty(cname):-1;
- if (absType && idx == -1)
- return false;
-
- subscribeName << name;
-
- if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) {
- absType = 0;
- if (!fetch(type, mo, reg, idx, subscribeName, nameNodes.at(ii)))
- return false;
- } else {
-
- Instr prop;
- if (ii == nameParts.count() -1 )
- prop.common.type = Instr::FindPropertyTerminal;
- else
- prop.common.type = Instr::FindProperty;
-
- prop.find.reg = reg;
- prop.find.src = reg;
- prop.find.name = registerString(name);
- prop.find.exceptionId = exceptionId(nameNodes.at(ii));
-
- if (subscription(subscribeName, &type))
- prop.find.subscribeIndex = subscriptionIndex(subscribeName);
- else
- prop.find.subscribeIndex = -1;
-
- type.unknownType = true;
- type.metaObject = 0;
- type.type = -1;
- type.reg = reg;
- bytecode << prop;
- }
- }
-
- wasAttachedObject = false;
- }
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryArith(QDeclarativeJS::AST::Node *node)
-{
- if (node->kind != AST::Node::Kind_BinaryExpression)
- return false;
-
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
- if (expression->op == QSOperator::Add ||
- expression->op == QSOperator::Sub)
- return true;
- else
- return false;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseArith(QDeclarativeJS::AST::Node *node, Result &type)
-{
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
-
- type.reg = acquireReg();
- if (type.reg == -1)
- return false;
-
- Result lhs;
- Result rhs;
-
- if (!parseExpression(expression->left, lhs)) return false;
- if (!parseExpression(expression->right, rhs)) return false;
-
- if ((lhs.type == QVariant::Int || lhs.type == QMetaType::QReal) &&
- (rhs.type == QVariant::Int || rhs.type == QMetaType::QReal))
- return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
- else if(expression->op == QSOperator::Sub)
- return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
- else if ((lhs.type == QMetaType::QString || lhs.unknownType) &&
- (rhs.type == QMetaType::QString || rhs.unknownType) &&
- (lhs.type == QMetaType::QString || rhs.type == QMetaType::QString))
- return stringArith(type, lhs, rhs, (QSOperator::Op)expression->op);
- else
- return false;
-}
-
-bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
-{
- bool nativeReal = rhs.type == QMetaType::QReal ||
- lhs.type == QMetaType::QReal ||
- lhs.unknownType ||
- rhs.unknownType;
-
- if (nativeReal && lhs.type == QMetaType::Int) {
- Instr convert;
- convert.common.type = Instr::ConvertIntToReal;
- convert.unaryop.output = lhs.reg;
- convert.unaryop.src = lhs.reg;
- bytecode << convert;
- }
-
- if (nativeReal && rhs.type == QMetaType::Int) {
- Instr convert;
- convert.common.type = Instr::ConvertIntToReal;
- convert.unaryop.output = rhs.reg;
- convert.unaryop.src = rhs.reg;
- bytecode << convert;
- }
-
- int lhsTmp = -1;
- int rhsTmp = -1;
-
- if (lhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- lhsTmp = acquireReg();
- if (lhsTmp == -1)
- return false;
-
- Instr conv;
- conv.common.type = Instr::ConvertGenericToReal;
- conv.unaryop.output = lhsTmp;
- conv.unaryop.src = lhs.reg;
- bytecode << conv;
- }
-
- if (rhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- rhsTmp = acquireReg();
- if (rhsTmp == -1)
- return false;
-
- Instr conv;
- conv.common.type = Instr::ConvertGenericToReal;
- conv.unaryop.output = rhsTmp;
- conv.unaryop.src = rhs.reg;
- bytecode << conv;
- }
-
- Instr arith;
- if (op == QSOperator::Add) {
- arith.common.type = nativeReal?Instr::AddReal:Instr::AddInt;
- } else if (op == QSOperator::Sub) {
- arith.common.type = nativeReal?Instr::MinusReal:Instr::MinusInt;
- } else {
- qFatal("Unsupported arithmetic operator");
- }
-
- arith.binaryop.output = type.reg;
- arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
- arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
- bytecode << arith;
-
- type.metaObject = 0;
- type.type = nativeReal?QMetaType::QReal:QMetaType::Int;
- type.subscriptionSet.unite(lhs.subscriptionSet);
- type.subscriptionSet.unite(rhs.subscriptionSet);
-
- if (lhsTmp != -1) releaseReg(lhsTmp);
- if (rhsTmp != -1) releaseReg(rhsTmp);
- releaseReg(lhs.reg);
- releaseReg(rhs.reg);
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
-{
- if (op != QSOperator::Add)
- return false;
-
- int lhsTmp = -1;
- int rhsTmp = -1;
-
- if (lhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- lhsTmp = acquireReg(Instr::CleanupString);
- if (lhsTmp == -1)
- return false;
-
- Instr convert;
- convert.common.type = Instr::ConvertGenericToString;
- convert.unaryop.output = lhsTmp;
- convert.unaryop.src = lhs.reg;
- bytecode << convert;
- }
-
- if (rhs.unknownType) {
- if (!qmlExperimental())
- return false;
-
- rhsTmp = acquireReg(Instr::CleanupString);
- if (rhsTmp == -1)
- return false;
-
- Instr convert;
- convert.common.type = Instr::ConvertGenericToString;
- convert.unaryop.output = rhsTmp;
- convert.unaryop.src = rhs.reg;
- bytecode << convert;
- }
-
- type.reg = acquireReg(Instr::CleanupString);
- if (type.reg == -1)
- return false;
-
- type.type = QMetaType::QString;
-
- Instr add;
- add.common.type = Instr::AddString;
- add.binaryop.output = type.reg;
- add.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
- add.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
- bytecode << add;
-
- if (lhsTmp != -1) releaseReg(lhsTmp);
- if (rhsTmp != -1) releaseReg(rhsTmp);
- releaseReg(lhs.reg);
- releaseReg(rhs.reg);
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryLogic(QDeclarativeJS::AST::Node *node)
-{
- if (node->kind != AST::Node::Kind_BinaryExpression)
- return false;
-
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
- if (expression->op == QSOperator::Gt ||
- expression->op == QSOperator::Equal ||
- expression->op == QSOperator::NotEqual)
- return true;
- else
- return false;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseLogic(QDeclarativeJS::AST::Node *node, Result &type)
-{
- AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
-
- Result lhs;
- Result rhs;
-
- if (!parseExpression(expression->left, lhs)) return false;
- if (!parseExpression(expression->right, rhs)) return false;
-
- type.reg = acquireReg();
- if (type.reg == -1)
- return false;
-
- type.metaObject = 0;
- type.type = QVariant::Bool;
-
- if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) {
-
- Instr op;
- if (expression->op == QSOperator::Gt)
- op.common.type = Instr::GreaterThanReal;
- else if (expression->op == QSOperator::Equal)
- op.common.type = Instr::CompareReal;
- else if (expression->op == QSOperator::NotEqual)
- op.common.type = Instr::NotCompareReal;
- else
- return false;
- op.binaryop.output = type.reg;
- op.binaryop.src1 = lhs.reg;
- op.binaryop.src2 = rhs.reg;
- bytecode << op;
-
-
- } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) {
-
- Instr op;
- if (expression->op == QSOperator::Equal)
- op.common.type = Instr::CompareString;
- else if (expression->op == QSOperator::NotEqual)
- op.common.type = Instr::NotCompareString;
- else
- return false;
- op.binaryop.output = type.reg;
- op.binaryop.src1 = lhs.reg;
- op.binaryop.src2 = rhs.reg;
- bytecode << op;
-
- } else {
- return false;
- }
-
- releaseReg(lhs.reg);
- releaseReg(rhs.reg);
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryConditional(QDeclarativeJS::AST::Node *node)
-{
- return (node->kind == AST::Node::Kind_ConditionalExpression);
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseConditional(QDeclarativeJS::AST::Node *node, Result &type)
-{
- AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node);
-
- AST::Node *test = expression->expression;
- if (test->kind == AST::Node::Kind_NestedExpression)
- test = static_cast<AST::NestedExpression*>(test)->expression;
-
- Result etype;
- if (!parseExpression(test, etype)) return false;
-
- if (etype.type != QVariant::Bool)
- return false;
-
- Instr skip;
- skip.common.type = Instr::Skip;
- skip.skip.reg = etype.reg;
- skip.skip.count = 0;
- int skipIdx = bytecode.count();
- bytecode << skip;
-
- // Release to allow reuse of reg
- releaseReg(etype.reg);
-
- QSet<QString> preSubSet = subscriptionSet;
-
- // int preConditionalSubscriptions = subscriptionSet.count();
-
- Result ok;
- if (!parseExpression(expression->ok, ok)) return false;
- if (ok.unknownType) return false;
-
- int skipIdx2 = bytecode.count();
- skip.skip.reg = -1;
- bytecode << skip;
-
- // Release to allow reuse of reg
- releaseReg(ok.reg);
- bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1;
-
- subscriptionSet = preSubSet;
-
- Result ko;
- if (!parseExpression(expression->ko, ko)) return false;
- if (ko.unknownType) return false;
-
- // Release to allow reuse of reg
- releaseReg(ko.reg);
- bytecode[skipIdx2].skip.count = bytecode.count() - skipIdx2 - 1;
-
- if (ok != ko)
- return false; // Must be same type and in same register
-
- subscriptionSet = preSubSet;
-
- if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet))
- return false; // Conditionals cannot introduce new subscriptions
-
- type = ok;
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryConstant(QDeclarativeJS::AST::Node *node)
-{
- return node->kind == AST::Node::Kind_TrueLiteral ||
- node->kind == AST::Node::Kind_FalseLiteral ||
- node->kind == AST::Node::Kind_NumericLiteral ||
- node->kind == AST::Node::Kind_StringLiteral;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseConstant(QDeclarativeJS::AST::Node *node, Result &type)
-{
- type.metaObject = 0;
- type.type = -1;
- type.reg = acquireReg();
- if (type.reg == -1)
- return false;
-
- if (node->kind == AST::Node::Kind_TrueLiteral) {
- type.type = QVariant::Bool;
- Instr instr;
- instr.common.type = Instr::Bool;
- instr.bool_value.reg = type.reg;
- instr.bool_value.value = true;
- bytecode << instr;
- return true;
- } else if (node->kind == AST::Node::Kind_FalseLiteral) {
- type.type = QVariant::Bool;
- Instr instr;
- instr.common.type = Instr::Bool;
- instr.bool_value.reg = type.reg;
- instr.bool_value.value = false;
- bytecode << instr;
- return true;
- } else if (node->kind == AST::Node::Kind_NumericLiteral) {
- qreal value = qreal(static_cast<AST::NumericLiteral *>(node)->value);
-
- if (qreal(float(value)) != value)
- return false;
-
- type.type = QMetaType::QReal;
- Instr instr;
- instr.common.type = Instr::Real;
- instr.real_value.reg = type.reg;
- instr.real_value.value = float(value);
- bytecode << instr;
- return true;
- } else if (node->kind == AST::Node::Kind_StringLiteral) {
- QString str = static_cast<AST::StringLiteral *>(node)->value->asString();
- type.type = QMetaType::QString;
- type.reg = registerLiteralString(str);
- return true;
- } else {
- return false;
- }
-}
-
-bool QDeclarativeBindingCompilerPrivate::tryMethod(QDeclarativeJS::AST::Node *node)
-{
- return node->kind == AST::Node::Kind_CallExpression;
-}
-
-bool QDeclarativeBindingCompilerPrivate::parseMethod(QDeclarativeJS::AST::Node *node, Result &result)
-{
- AST::CallExpression *expr = static_cast<AST::CallExpression *>(node);
-
- QStringList name;
- if (!buildName(name, expr->base))
- return false;
-
- if (name.count() != 2 || name.at(0) != QLatin1String("Math"))
- return false;
-
- QString method = name.at(1);
-
- AST::ArgumentList *args = expr->arguments;
- if (!args) return false;
- AST::ExpressionNode *arg0 = args->expression;
- args = args->next;
- if (!args) return false;
- AST::ExpressionNode *arg1 = args->expression;
- if (args->next != 0) return false;
- if (!arg0 || !arg1) return false;
-
- Result r0;
- if (!parseExpression(arg0, r0)) return false;
- Result r1;
- if (!parseExpression(arg1, r1)) return false;
-
- if (r0.type != QMetaType::QReal || r1.type != QMetaType::QReal)
- return false;
-
- Instr op;
- if (method == QLatin1String("max")) {
- op.common.type = Instr::MaxReal;
- } else if (method == QLatin1String("min")) {
- op.common.type = Instr::MinReal;
- } else {
- return false;
- }
- // We release early to reuse registers
- releaseReg(r0.reg);
- releaseReg(r1.reg);
-
- op.binaryop.output = acquireReg();
- if (op.binaryop.output == -1)
- return false;
-
- op.binaryop.src1 = r0.reg;
- op.binaryop.src2 = r1.reg;
- bytecode << op;
-
- result.type = QMetaType::QReal;
- result.reg = op.binaryop.output;
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::buildName(QStringList &name,
- QDeclarativeJS::AST::Node *node,
- QList<QDeclarativeJS::AST::ExpressionNode *> *nodes)
-{
- if (node->kind == AST::Node::Kind_IdentifierExpression) {
- name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
- if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
- } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
- AST::FieldMemberExpression *expr =
- static_cast<AST::FieldMemberExpression *>(node);
-
- if (!buildName(name, expr->base, nodes))
- return false;
-
- name << expr->name->asString();
- if (nodes) *nodes << expr;
- } else {
- return false;
- }
-
- return true;
-}
-
-bool QDeclarativeBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg,
- int idx, const QStringList &subName,
- QDeclarativeJS::AST::ExpressionNode *node)
-{
- QMetaProperty prop = mo->property(idx);
- rv.metaObject = 0;
- rv.type = 0;
-
- //XXX binding optimizer doesn't handle properties with a revision
- if (prop.revision() > 0)
- return false;
-
- int fastFetchIndex = fastProperties()->accessorIndexForProperty(mo, idx);
-
- Instr fetch;
-
- if (!qmlDisableFastProperties() && fastFetchIndex != -1) {
- fetch.common.type = Instr::FetchAndSubscribe;
- fetch.fetchAndSubscribe.objectReg = reg;
- fetch.fetchAndSubscribe.output = reg;
- fetch.fetchAndSubscribe.function = fastFetchIndex;
- fetch.fetchAndSubscribe.subscription = subscriptionIndex(subName);
- fetch.fetchAndSubscribe.exceptionId = exceptionId(node);
- } else {
- if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
- Instr sub;
- sub.common.type = Instr::Subscribe;
- sub.subscribe.offset = subscriptionIndex(subName);
- sub.subscribe.reg = reg;
- sub.subscribe.index = prop.notifySignalIndex();
- bytecode << sub;
- }
-
- fetch.common.type = Instr::Fetch;
- fetch.fetch.objectReg = reg;
- fetch.fetch.index = idx;
- fetch.fetch.output = reg;
- fetch.fetch.exceptionId = exceptionId(node);
- }
-
- rv.type = prop.userType();
- rv.metaObject = engine->metaObjectForType(rv.type);
- rv.reg = reg;
-
- if (rv.type == QMetaType::QString) {
- int tmp = acquireReg();
- if (tmp == -1)
- return false;
- Instr copy;
- copy.common.type = Instr::Copy;
- copy.copy.reg = tmp;
- copy.copy.src = reg;
- bytecode << copy;
- releaseReg(tmp);
- fetch.fetch.objectReg = tmp;
-
- Instr setup;
- setup.common.type = Instr::NewString;
- setup.construct.reg = reg;
- bytecode << setup;
- registerCleanup(reg, Instr::CleanupString);
- }
-
- bytecode << fetch;
-
- if (!rv.metaObject &&
- rv.type != QMetaType::QReal &&
- rv.type != QMetaType::Int &&
- rv.type != QMetaType::Bool &&
- rv.type != qMetaTypeId<QDeclarativeAnchorLine>() &&
- rv.type != QMetaType::QString) {
- rv.metaObject = 0;
- rv.type = 0;
- return false; // Unsupported type (string not supported yet);
- }
-
- return true;
-}
-
-void QDeclarativeBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType)
-{
- registerCleanups.insert(reg, qMakePair(cleanup, cleanupType));
-}
-
-int QDeclarativeBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType)
-{
- for (int ii = 0; ii < 32; ++ii) {
- if (!(registers & (1 << ii))) {
- registers |= (1 << ii);
-
- if (cleanup != Instr::Noop)
- registerCleanup(ii, cleanup, cleanupType);
-
- return ii;
- }
- }
- return -1;
-}
-
-void QDeclarativeBindingCompilerPrivate::releaseReg(int reg)
-{
- Q_ASSERT(reg >= 0 && reg <= 31);
-
- if (registerCleanups.contains(reg)) {
- QPair<int, int> c = registerCleanups[reg];
- registerCleanups.remove(reg);
- Instr cleanup;
- cleanup.common.type = (quint8)c.first;
- cleanup.cleanup.reg = reg;
- bytecode << cleanup;
- }
-
- quint32 mask = 1 << reg;
- registers &= ~mask;
-}
-
-// Returns a reg
-int QDeclarativeBindingCompilerPrivate::registerLiteralString(const QString &str)
-{
- QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
- int offset = data.count();
- data += strdata;
-
- int reg = acquireReg(Instr::CleanupString);
- if (reg == -1)
- return false;
-
- Instr string;
- string.common.type = Instr::String;
- string.string_value.reg = reg;
- string.string_value.offset = offset;
- string.string_value.length = str.length();
- bytecode << string;
-
- return reg;
-}
-
-// Returns an identifier offset
-int QDeclarativeBindingCompilerPrivate::registerString(const QString &string)
-{
- Q_ASSERT(!string.isEmpty());
-
- QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
-
- if (iter == registeredStrings.end()) {
- quint32 len = string.length();
- QByteArray lendata((const char *)&len, sizeof(quint32));
- QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
- strdata.prepend(lendata);
- int rv = data.count();
- data += strdata;
-
- iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv));
- }
-
- Instr reg;
- reg.common.type = Instr::InitString;
- reg.initstring.offset = iter->first;
- reg.initstring.dataIdx = iter->second;
- bytecode << reg;
- return reg.initstring.offset;
-}
-
-bool QDeclarativeBindingCompilerPrivate::subscription(const QStringList &sub, Result *result)
-{
- QString str = sub.join(QLatin1String("."));
- result->subscriptionSet.insert(str);
-
- if (subscriptionSet.contains(str)) {
- return false;
- } else {
- subscriptionSet.insert(str);
- return true;
- }
-}
-
-int QDeclarativeBindingCompilerPrivate::subscriptionIndex(const QStringList &sub)
-{
- QString str = sub.join(QLatin1String("."));
- QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
- if (iter == subscriptionIds.end())
- iter = subscriptionIds.insert(str, subscriptionIds.count());
- usedSubscriptionIds.insert(*iter);
- return *iter;
-}
-
-/*
- Returns true if lhs contains no subscriptions that aren't also in base or rhs AND
- rhs contains no subscriptions that aren't also in base or lhs.
-*/
-bool QDeclarativeBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base,
- const QSet<QString> &lhs,
- const QSet<QString> &rhs)
-{
- QSet<QString> difflhs = lhs;
- difflhs.subtract(rhs);
- QSet<QString> diffrhs = rhs;
- diffrhs.subtract(lhs);
-
- difflhs.unite(diffrhs);
- difflhs.subtract(base);
-
- return difflhs.isEmpty();
-}
-
-quint8 QDeclarativeBindingCompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
-{
- quint8 rv = 0xFF;
- if (n && exceptions.count() < 0xFF) {
- rv = (quint8)exceptions.count();
- QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
- quint64 e = l.startLine;
- e <<= 32;
- e |= l.startColumn;
- exceptions.append(e);
- }
- return rv;
-}
-
-QDeclarativeBindingCompiler::QDeclarativeBindingCompiler()
-: d(new QDeclarativeBindingCompilerPrivate)
-{
-}
-
-QDeclarativeBindingCompiler::~QDeclarativeBindingCompiler()
-{
- delete d; d = 0;
-}
-
-/*
-Returns true if any bindings were compiled.
-*/
-bool QDeclarativeBindingCompiler::isValid() const
-{
- return !d->committed.bytecode.isEmpty();
-}
-
-/*
--1 on failure, otherwise the binding index to use.
-*/
-int QDeclarativeBindingCompiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
-{
- if (!expression.expression.asAST()) return false;
-
- if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
- return -1;
-
- if (qmlDisableOptimizer())
- return -1;
-
- d->context = expression.context;
- d->component = expression.component;
- d->destination = expression.property;
- d->ids = expression.ids;
- d->imports = expression.imports;
- d->engine = engine;
-
- if (d->compile(expression.expression.asAST())) {
- return d->commitCompile();
- } else {
- return -1;
- }
-}
-
-
-QByteArray QDeclarativeBindingCompilerPrivate::buildSignalTable() const
-{
- QHash<int, QList<int> > table;
-
- for (int ii = 0; ii < committed.count(); ++ii) {
- const QSet<int> &deps = committed.dependencies.at(ii);
- for (QSet<int>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter)
- table[*iter].append(ii);
- }
-
- QVector<quint32> header;
- QVector<quint32> data;
- for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
- header.append(committed.subscriptionIds.count() + data.count());
- const QList<int> &bindings = table[ii];
- data.append(bindings.count());
- for (int jj = 0; jj < bindings.count(); ++jj)
- data.append(bindings.at(jj));
- }
- header << data;
-
- return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
-}
-
-QByteArray QDeclarativeBindingCompilerPrivate::buildExceptionData() const
-{
- QByteArray rv;
- rv.resize(committed.exceptions.count() * sizeof(quint64));
- ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
- return rv;
-}
-
-/*
-Returns the compiled program.
-*/
-QByteArray QDeclarativeBindingCompiler::program() const
-{
- QByteArray programData;
-
- if (isValid()) {
- Program prog;
- prog.bindings = d->committed.count();
-
- QVector<Instr> bytecode;
- Instr skip;
- skip.common.type = Instr::Skip;
- skip.skip.reg = -1;
- for (int ii = 0; ii < d->committed.count(); ++ii) {
- skip.skip.count = d->committed.count() - ii - 1;
- skip.skip.count+= d->committed.offsets.at(ii);
- bytecode << skip;
- }
- bytecode << d->committed.bytecode;
-
- QByteArray data = d->committed.data;
- while (data.count() % 4) data.append('\0');
- prog.signalTableOffset = data.count();
- data += d->buildSignalTable();
- while (data.count() % 4) data.append('\0');
- prog.exceptionDataOffset = data.count();
- data += d->buildExceptionData();
-
- prog.dataLength = 4 * ((data.size() + 3) / 4);
- prog.subscriptions = d->committed.subscriptionIds.count();
- prog.identifiers = d->committed.registeredStrings.count();
- prog.instructionCount = bytecode.count();
- prog.compiled = false;
- int size = sizeof(Program) + bytecode.count() * sizeof(Instr);
- size += prog.dataLength;
-
- programData.resize(size);
- memcpy(programData.data(), &prog, sizeof(Program));
- if (prog.dataLength)
- memcpy((char *)((Program *)programData.data())->data(), data.constData(),
- data.size());
- memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(),
- bytecode.count() * sizeof(Instr));
- }
-
- return programData;
-}
-
-
-
-QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompileddata.cpp b/src/declarative/qml/qdeclarativecompileddata.cpp
index 03deea1e36..3d1e9255ad 100644
--- a/src/declarative/qml/qdeclarativecompileddata.cpp
+++ b/src/declarative/qml/qdeclarativecompileddata.cpp
@@ -181,6 +181,9 @@ QDeclarativeCompiledData::~QDeclarativeCompiledData()
for (int ii = 0; ii < contextCaches.count(); ++ii)
contextCaches.at(ii)->release();
+ for (int ii = 0; ii < scripts.count(); ++ii)
+ scripts.at(ii)->release();
+
if (importCache)
importCache->release();
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp
index f57f842004..d325ac48dd 100644
--- a/src/declarative/qml/qdeclarativecompiler.cpp
+++ b/src/declarative/qml/qdeclarativecompiler.cpp
@@ -63,7 +63,7 @@
#include "private/qdeclarativeglobal_p.h"
#include "private/qdeclarativescriptparser_p.h"
#include "private/qdeclarativebinding_p.h"
-#include "private/qdeclarativecompiledbindings_p.h"
+#include "private/qdeclarativev4compiler_p.h"
#include "private/qdeclarativeglobalscriptclass_p.h"
#include <QColor>
@@ -79,7 +79,6 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
-DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
using namespace QDeclarativeParser;
@@ -201,6 +200,9 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
case QVariant::String:
if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
break;
+ case QVariant::ByteArray:
+ if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
+ break;
case QVariant::Url:
if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
break;
@@ -320,16 +322,20 @@ bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
QDeclarativeParser::Value *v)
{
- QString string = v->value.asString();
-
QDeclarativeInstruction instr;
instr.line = v->location.start.line;
if (prop.isEnumType()) {
int value;
- if (prop.isFlagType()) {
- value = prop.enumerator().keysToValue(string.toUtf8().constData());
- } else
- value = prop.enumerator().keyToValue(string.toUtf8().constData());
+ if (v->value.isNumber()) {
+ // Preresolved enum
+ value = (int)v->value.asNumber();
+ } else {
+ // Must be a string
+ if (prop.isFlagType()) {
+ value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData());
+ } else
+ value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData());
+ }
instr.type = QDeclarativeInstruction::StoreInteger;
instr.storeInteger.propertyIndex = prop.propertyIndex();
@@ -338,6 +344,8 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
return;
}
+ QString string = v->value.asString();
+
int type = prop.userType();
switch(type) {
case -1:
@@ -371,6 +379,13 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
instr.storeString.value = output->indexForString(string);
}
break;
+ case QVariant::ByteArray:
+ {
+ instr.type = QDeclarativeInstruction::StoreByteArray;
+ instr.storeByteArray.propertyIndex = prop.propertyIndex();
+ instr.storeByteArray.value = output->indexForByteArray(string.toLatin1());
+ }
+ break;
case QVariant::Url:
{
instr.type = QDeclarativeInstruction::StoreUrl;
@@ -642,6 +657,31 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
compileState.root = tree;
componentStat.lineNumber = tree->location.start.line;
+ // Build global import scripts
+ QStringList importedScriptIndexes;
+
+ foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
+ importedScriptIndexes.append(script.qualifier);
+
+ QDeclarativeInstruction import;
+ import.type = QDeclarativeInstruction::StoreImportedScript;
+ import.line = 0;
+ import.storeScript.value = output->scripts.count();
+
+ QDeclarativeScriptData *scriptData = script.script->scriptData();
+ scriptData->addref();
+ output->scripts << scriptData;
+ output->bytecode << import;
+ }
+
+ // We generate the importCache before we build the tree so that
+ // it can be used in the binding compiler. Given we "expect" the
+ // QML compilation to succeed, this isn't a waste.
+ output->importCache = new QDeclarativeTypeNameCache(engine);
+ for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
+ output->importCache->add(importedScriptIndexes.at(ii), ii);
+ unit->imports().populateCache(output->importCache, engine);
+
if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
return;
@@ -657,38 +697,6 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
output->bytecode << init;
- // Build global import scripts
- QHash<QString, Object::ScriptBlock> importedScripts;
- QStringList importedScriptIndexes;
-
- foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
- QString scriptCode = script.script->scriptSource();
- Object::ScriptBlock::Pragmas pragmas = script.script->pragmas();
-
- Q_ASSERT(!importedScripts.contains(script.qualifier));
-
- if (!scriptCode.isEmpty()) {
- Object::ScriptBlock &scriptBlock = importedScripts[script.qualifier];
-
- scriptBlock.code = scriptCode;
- scriptBlock.file = script.script->finalUrl().toString();
- scriptBlock.pragmas = pragmas;
- }
- }
-
- for (QHash<QString, Object::ScriptBlock>::Iterator iter = importedScripts.begin();
- iter != importedScripts.end(); ++iter) {
-
- importedScriptIndexes.append(iter.key());
-
- QDeclarativeInstruction import;
- import.type = QDeclarativeInstruction::StoreImportedScript;
- import.line = 0;
- import.storeScript.value = output->scripts.count();
- output->scripts << *iter;
- output->bytecode << import;
- }
-
genObject(tree);
QDeclarativeInstruction def;
@@ -696,13 +704,6 @@ void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
def.type = QDeclarativeInstruction::SetDefault;
output->bytecode << def;
- output->importCache = new QDeclarativeTypeNameCache(engine);
-
- for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
- output->importCache->add(importedScriptIndexes.at(ii), ii);
-
- unit->imports().populateCache(output->importCache, engine);
-
Q_ASSERT(tree->metatype);
if (tree->metadata.isEmpty()) {
@@ -1283,6 +1284,7 @@ bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *ob
compileState = ComponentCompileState();
compileState.root = obj;
+ compileState.nested = true;
componentStat = ComponentStat();
componentStat.lineNumber = obj->location.start.line;
@@ -1442,8 +1444,6 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
if (typeNamespace) {
- // ### We might need to indicate that this property is a namespace
- // for the DOM API
COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
ctxt));
return true;
@@ -2227,20 +2227,35 @@ bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop
objTypeName = objType->qmlTypeName();
}
- if (!type || objTypeName != type->qmlTypeName())
+ if (!type)
return true;
QString enumValue = parts.at(1);
- int value;
- if (prop.isFlagType()) {
- value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
- } else
- value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
+ int value = -1;
+
+ if (objTypeName == type->qmlTypeName()) {
+ // When these two match, we can short cut the search
+ if (prop.isFlagType()) {
+ value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
+ } else {
+ value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
+ }
+ } else {
+ // Otherwise we have to search the whole type
+ // This matches the logic in QDeclarativeTypeNameScriptClass
+ QByteArray enumName = enumValue.toUtf8();
+ const QMetaObject *metaObject = type->baseMetaObject();
+ for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ value = e.keyToValue(enumName.constData());
+ }
+ }
+
if (value == -1)
return true;
v->type = Value::Literal;
- v->value = QDeclarativeParser::Variant(enumValue);
+ v->value = QDeclarativeParser::Variant((double)value);
*isAssignment = true;
return true;
@@ -2412,7 +2427,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
newClassName.append("_QML_");
int idx = classIndexCounter()->fetchAndAddRelaxed(1);
newClassName.append(QByteArray::number(idx));
- if (compileState.root == obj) {
+ if (compileState.root == obj && !compileState.nested) {
QString path = output->url.path();
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
if (lastSlash > -1) {
@@ -2888,25 +2903,26 @@ bool QDeclarativeCompiler::completeComponentBuild()
COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
}
- QDeclarativeBindingCompiler::Expression expr;
+ QDeclarativeV4Compiler::Expression expr;
expr.component = compileState.root;
expr.ids = compileState.ids;
+ expr.importCache = output->importCache;
+ expr.imports = unit->imports();
- QDeclarativeBindingCompiler bindingCompiler;
+ QDeclarativeV4Compiler bindingCompiler;
for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
iter != compileState.bindings.end(); ++iter) {
BindingReference &binding = *iter;
- expr.context = binding.bindingContext.object;
- expr.property = binding.property;
- expr.expression = binding.expression;
- expr.imports = unit->imports();
-
// ### We don't currently optimize for bindings on alias's - because
// of the solution to QTBUG-13719
if (!binding.property->isAlias) {
+ expr.context = binding.bindingContext.object;
+ expr.property = binding.property;
+ expr.expression = binding.expression;
+
int index = bindingCompiler.compile(expr, enginePrivate);
if (index != -1) {
binding.dataType = BindingReference::Experimental;
@@ -2947,11 +2963,8 @@ bool QDeclarativeCompiler::completeComponentBuild()
componentStat.scriptBindings.append(iter.key()->location);
}
- if (bindingCompiler.isValid()) {
+ if (bindingCompiler.isValid())
compileState.compiledBindingData = bindingCompiler.program();
- if (bindingsDump())
- QDeclarativeBindingCompiler::dump(compileState.compiledBindingData);
- }
saveComponentState();
diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h
index 93b6a0961e..49bab759be 100644
--- a/src/declarative/qml/qdeclarativecompiler_p.h
+++ b/src/declarative/qml/qdeclarativecompiler_p.h
@@ -122,7 +122,7 @@ public:
QList<QScriptValue *> cachedClosures;
QList<QDeclarativePropertyCache *> propertyCaches;
QList<QDeclarativeIntegerCache *> contextCaches;
- QList<QDeclarativeParser::Object::ScriptBlock> scripts;
+ QList<QDeclarativeScriptData *> scripts;
QList<QUrl> urls;
void dumpInstructions();
@@ -305,11 +305,12 @@ private:
struct ComponentCompileState
{
ComponentCompileState()
- : parserStatusCount(0), pushedProperties(0), root(0) {}
+ : parserStatusCount(0), pushedProperties(0), nested(false), root(0) {}
QHash<QString, QDeclarativeParser::Object *> ids;
QHash<int, QDeclarativeParser::Object *> idIndexes;
int parserStatusCount;
int pushedProperties;
+ bool nested;
QByteArray compiledBindingData;
diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp
index 8238252db2..aa1bbd156f 100644
--- a/src/declarative/qml/qdeclarativecomponent.cpp
+++ b/src/declarative/qml/qdeclarativecomponent.cpp
@@ -836,6 +836,34 @@ QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, cons
return begin(context, creationContext, cc, start, count, &state, 0, bindings);
}
+/*
+ Try to do what's necessary for a reasonable display of the type
+ name, but no more (just enough for the client to do more extensive cleanup).
+
+ Should only be called when debugging is enabled.
+*/
+static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
+{
+ static const QString qmlMarker(QLatin1String("_QML"));
+ static const QChar underscore(QLatin1Char('_'));
+ static const QChar asterisk(QLatin1Char('*'));
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(metaObject);
+ QString typeName = type ? QLatin1String(type->qmlTypeName()) : QLatin1String(metaObject->className());
+ if (!type) {
+ //### optimize further?
+ int marker = typeName.indexOf(qmlMarker);
+ if (marker != -1 && marker < typeName.count() - 1) {
+ if (typeName[marker + 1] == underscore) {
+ const QString className = typeName.left(marker) + asterisk;
+ type = QDeclarativeMetaType::qmlType(QMetaType::type(className.toLatin1()));
+ if (type)
+ typeName = QLatin1String(type->qmlTypeName());
+ }
+ }
+ }
+ return typeName;
+}
+
QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentContext,
QDeclarativeContextData *componentCreationContext,
QDeclarativeCompiledData *component, int start, int count,
@@ -848,10 +876,8 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
Q_ASSERT(!isRoot || state); // Either this isn't a root component, or a state data must be provided
Q_ASSERT((state != 0) ^ (errors != 0)); // One of state or errors (but not both) must be provided
- if (isRoot) {
+ if (isRoot)
QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
- QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, component->url);
- }
QDeclarativeContextData *ctxt = new QDeclarativeContextData;
ctxt->isInternal = true;
@@ -868,7 +894,9 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
enginePriv->inBeginCreate = true;
QDeclarativeVME vme;
+ enginePriv->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
QObject *rv = vme.run(ctxt, component, start, count, bindings);
+ enginePriv->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
if (vme.isError()) {
if(errors) *errors = vme.errors();
@@ -897,6 +925,11 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
if (!parentContext->isInternal)
parentContext->asQDeclarativeContextPrivate()->instances.append(rv);
QDeclarativeEngineDebugServer::instance()->objectCreated(parentContext->engine, rv);
+ if (isRoot) {
+ QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, buildTypeNameForDebug(rv->metaObject()));
+ QDeclarativeData *data = QDeclarativeData::get(rv);
+ QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Creating, component->url, data ? data->lineNumber : -1);
+ }
}
return rv;
diff --git a/src/declarative/qml/qdeclarativecomponent.h b/src/declarative/qml/qdeclarativecomponent.h
index 9a60a8b4f7..f46ffdf2cf 100644
--- a/src/declarative/qml/qdeclarativecomponent.h
+++ b/src/declarative/qml/qdeclarativecomponent.h
@@ -117,7 +117,6 @@ private:
Q_DISABLE_COPY(QDeclarativeComponent)
friend class QDeclarativeVME;
- friend class QDeclarativeCompositeTypeData;
friend class QDeclarativeTypeData;
};
diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp
index 7637b72eb3..4f0d704d95 100644
--- a/src/declarative/qml/qdeclarativecontext.cpp
+++ b/src/declarative/qml/qdeclarativecontext.cpp
@@ -46,9 +46,9 @@
#include "private/qdeclarativeexpression_p.h"
#include "private/qdeclarativeengine_p.h"
#include "qdeclarativeengine.h"
-#include "private/qdeclarativecompiledbindings_p.h"
#include "qdeclarativeinfo.h"
#include "private/qdeclarativeglobalscriptclass_p.h"
+#include "private/qdeclarativev4bindings_p.h"
#include <qscriptengine.h>
#include <QtCore/qvarlengtharray.h>
@@ -498,7 +498,7 @@ QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject
QDeclarativeContextData::QDeclarativeContextData()
-: parent(0), engine(0), isInternal(false), publicContext(0), propertyNames(0), contextObject(0),
+: parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(0), propertyNames(0), contextObject(0),
imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
componentAttached(0)
@@ -506,7 +506,7 @@ QDeclarativeContextData::QDeclarativeContextData()
}
QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
-: parent(0), engine(0), isInternal(false), publicContext(ctxt), propertyNames(0), contextObject(0),
+: parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(ctxt), propertyNames(0), contextObject(0),
imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
componentAttached(0)
@@ -515,8 +515,13 @@ QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
void QDeclarativeContextData::invalidate()
{
- while (childContexts)
- childContexts->invalidate();
+ while (childContexts) {
+ if (childContexts->ownedByParent) {
+ childContexts->destroy();
+ } else {
+ childContexts->invalidate();
+ }
+ }
while (componentAttached) {
QDeclarativeComponentAttached *a = componentAttached;
@@ -614,7 +619,7 @@ void QDeclarativeContextData::destroy()
delete this;
}
-void QDeclarativeContextData::setParent(QDeclarativeContextData *p)
+void QDeclarativeContextData::setParent(QDeclarativeContextData *p, bool parentTakesOwnership)
{
if (p) {
parent = p;
@@ -623,6 +628,7 @@ void QDeclarativeContextData::setParent(QDeclarativeContextData *p)
if (nextChild) nextChild->prevChild = &nextChild;
prevChild = &p->childContexts;
p->childContexts = this;
+ ownedByParent = parentTakesOwnership;
}
}
@@ -662,72 +668,6 @@ void QDeclarativeContextData::addObject(QObject *o)
contextObjects = data;
}
-void QDeclarativeContextData::addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script)
-{
- if (!engine)
- return;
-
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- const QString &code = script.code;
- const QString &url = script.file;
- const QDeclarativeParser::Object::ScriptBlock::Pragmas &pragmas = script.pragmas;
-
- Q_ASSERT(!url.isEmpty());
-
- if (pragmas & QDeclarativeParser::Object::ScriptBlock::Shared) {
-
- QHash<QString, QScriptValue>::Iterator iter = enginePriv->m_sharedScriptImports.find(url);
- if (iter == enginePriv->m_sharedScriptImports.end()) {
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
-
- scriptContext->pushScope(enginePriv->contextClass->newUrlContext(url));
- scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
-
- QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
- scriptContext->pushScope(scope);
-
- scriptEngine->evaluate(code, url, 1);
-
- if (scriptEngine->hasUncaughtException()) {
- QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
- enginePriv->warning(error);
- }
-
- scriptEngine->popContext();
-
- iter = enginePriv->m_sharedScriptImports.insert(url, scope);
- }
-
- importedScripts.append(*iter);
-
- } else {
-
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
-
- scriptContext->pushScope(enginePriv->contextClass->newUrlContext(this, 0, url));
- scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
-
- QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
- scriptContext->pushScope(scope);
-
- scriptEngine->evaluate(code, url, 1);
-
- if (scriptEngine->hasUncaughtException()) {
- QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
- enginePriv->warning(error);
- }
-
- scriptEngine->popContext();
-
- importedScripts.append(scope);
-
- }
-}
-
void QDeclarativeContextData::setIdProperty(int idx, QObject *obj)
{
idValues[idx] = obj;
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
index b7e4c6aa7c..29ca091fc2 100644
--- a/src/declarative/qml/qdeclarativecontext_p.h
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -77,7 +77,7 @@ class QDeclarativeEngine;
class QDeclarativeExpression;
class QDeclarativeExpressionPrivate;
class QDeclarativeAbstractExpression;
-class QDeclarativeCompiledBindings;
+class QDeclarativeV4Bindings;
class QDeclarativeContextData;
class QDeclarativeContextPrivate : public QObjectPrivate
@@ -124,7 +124,7 @@ public:
QDeclarativeContextData *parent;
QDeclarativeEngine *engine;
- void setParent(QDeclarativeContextData *);
+ void setParent(QDeclarativeContextData *, bool parentTakesOwnership = false);
void refreshExpressions();
void addObject(QObject *);
@@ -135,7 +135,9 @@ public:
// If internal is false publicContext owns this.
QDeclarativeContext *asQDeclarativeContext();
QDeclarativeContextPrivate *asQDeclarativeContextPrivate();
- bool isInternal;
+ quint32 isInternal:1;
+ quint32 ownedByParent:1; // unrelated to isInternal; parent context deletes children if true.
+ quint32 dummy:30;
QDeclarativeContext *publicContext;
// Property name cache
@@ -146,7 +148,6 @@ public:
// Any script blocks that exist on this context
QList<QScriptValue> importedScripts;
- void addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script);
// Context base url
QUrl url;
@@ -188,7 +189,7 @@ public:
void setIdPropertyData(QDeclarativeIntegerCache *);
// Optimized binding pointer
- QDeclarativeCompiledBindings *optimizedBindings;
+ QDeclarativeV4Bindings *optimizedBindings;
// Linked contexts. this owns linkedContext.
QDeclarativeContextData *linkedContext;
diff --git a/src/declarative/qml/qdeclarativedirparser.cpp b/src/declarative/qml/qdeclarativedirparser.cpp
index b5ad33d63e..97f7f4dda8 100644
--- a/src/declarative/qml/qdeclarativedirparser.cpp
+++ b/src/declarative/qml/qdeclarativedirparser.cpp
@@ -142,7 +142,7 @@ bool QDeclarativeDirParser::parse()
} else if (sections[0] == QLatin1String("plugin")) {
if (sectionCount < 2) {
reportError(lineNumber, -1,
- QString::fromUtf8("plugin directive requires 2 arguments, but %1 were provided").arg(sectionCount + 1));
+ QString::fromUtf8("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1));
continue;
}
@@ -154,12 +154,22 @@ bool QDeclarativeDirParser::parse()
} else if (sections[0] == QLatin1String("internal")) {
if (sectionCount != 3) {
reportError(lineNumber, -1,
- QString::fromUtf8("internal types require 2 arguments, but %1 were provided").arg(sectionCount + 1));
+ QString::fromUtf8("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1));
continue;
}
Component entry(sections[1], sections[2], -1, -1);
entry.internal = true;
_components.append(entry);
+ } else if (sections[0] == QLatin1String("typeinfo")) {
+ if (sectionCount != 2) {
+ reportError(lineNumber, -1,
+ QString::fromUtf8("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1));
+ continue;
+ }
+#ifdef QT_CREATOR
+ TypeInfo typeInfo(sections[1]);
+ _typeInfos.append(typeInfo);
+#endif
} else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files)
@@ -189,7 +199,7 @@ bool QDeclarativeDirParser::parse()
}
} else {
reportError(lineNumber, -1,
- QString::fromUtf8("a component declaration requires 3 arguments, but %1 were provided").arg(sectionCount + 1));
+ QString::fromUtf8("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount));
}
}
@@ -229,4 +239,11 @@ QList<QDeclarativeDirParser::Component> QDeclarativeDirParser::components() cons
return _components;
}
+#ifdef QT_CREATOR
+QList<TypeInfo> QDeclarativeDirParser::typeInfos() const
+{
+ return _typeInfos;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativedirparser_p.h b/src/declarative/qml/qdeclarativedirparser_p.h
index 95f14bc487..d09b90e7a2 100644
--- a/src/declarative/qml/qdeclarativedirparser_p.h
+++ b/src/declarative/qml/qdeclarativedirparser_p.h
@@ -109,6 +109,19 @@ public:
QList<Component> components() const;
QList<Plugin> plugins() const;
+#ifdef QT_CREATOR
+ struct TypeInfo
+ {
+ TypeInfo() {}
+ TypeInfo(const QString &fileName)
+ : fileName(fileName) {}
+
+ QString fileName;
+ };
+
+ QList<TypeInfo> typeInfos() const;
+#endif
+
private:
void reportError(int line, int column, const QString &message);
@@ -118,6 +131,9 @@ private:
QString _source;
QList<Component> _components;
QList<Plugin> _plugins;
+#ifdef QT_CREATOR
+ QList<TypeInfo> _typeInfos;
+#endif
unsigned _isParsed: 1;
};
diff --git a/src/declarative/qml/qdeclarativedom.cpp b/src/declarative/qml/qdeclarativedom.cpp
deleted file mode 100644
index f1296aaf18..0000000000
--- a/src/declarative/qml/qdeclarativedom.cpp
+++ /dev/null
@@ -1,1835 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativedom_p.h"
-#include "private/qdeclarativedom_p_p.h"
-
-#include "private/qdeclarativecompiler_p.h"
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativescriptparser_p.h"
-#include "private/qdeclarativeglobal_p.h"
-
-#include <QtCore/QByteArray>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
-
-QT_BEGIN_NAMESPACE
-
-QDeclarativeDomDocumentPrivate::QDeclarativeDomDocumentPrivate()
-: root(0)
-{
-}
-
-QDeclarativeDomDocumentPrivate::~QDeclarativeDomDocumentPrivate()
-{
- if (root) root->release();
-}
-
-/*!
- \class QDeclarativeDomDocument
- \internal
- \brief The QDeclarativeDomDocument class represents the root of a QML document
-
- A QML document is a self-contained snippet of QML, usually contained in a
- single file. Each document has a root object, accessible through
- QDeclarativeDomDocument::rootObject().
-
- The QDeclarativeDomDocument class allows the programmer to inspect a QML document by
- calling QDeclarativeDomDocument::load().
-
- The following example loads a QML file from disk, and prints out its root
- object type and the properties assigned in the root object.
- \code
- QFile file(inputFileName);
- file.open(QIODevice::ReadOnly);
- QByteArray xmlData = file.readAll();
-
- QDeclarativeDomDocument document;
- document.load(qmlengine, xmlData);
-
- QDeclarativeDomObject rootObject = document.rootObject();
- qDebug() << rootObject.objectType();
- foreach(QDeclarativeDomProperty property, rootObject.properties())
- qDebug() << property.propertyName();
- \endcode
-*/
-
-/*!
- Construct an empty QDeclarativeDomDocument.
-*/
-QDeclarativeDomDocument::QDeclarativeDomDocument()
-: d(new QDeclarativeDomDocumentPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomDocument.
-*/
-QDeclarativeDomDocument::QDeclarativeDomDocument(const QDeclarativeDomDocument &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomDocument
-*/
-QDeclarativeDomDocument::~QDeclarativeDomDocument()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomDocument.
-*/
-QDeclarativeDomDocument &QDeclarativeDomDocument::operator=(const QDeclarativeDomDocument &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns all import statements in qml.
-*/
-QList<QDeclarativeDomImport> QDeclarativeDomDocument::imports() const
-{
- return d->imports;
-}
-
-/*!
- Loads a QDeclarativeDomDocument from \a data. \a data should be valid QML
- data. On success, true is returned. If the \a data is malformed, false
- is returned and QDeclarativeDomDocument::errors() contains an error description.
-
- \sa QDeclarativeDomDocument::loadError()
-*/
-bool QDeclarativeDomDocument::load(QDeclarativeEngine *engine, const QByteArray &data, const QUrl &url)
-{
- d->errors.clear();
- d->imports.clear();
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QDeclarativeTypeData *td = ep->typeLoader.get(data, url, QDeclarativeTypeLoader::PreserveParser);
-
- if(td->isError()) {
- d->errors = td->errors();
- td->release();
- return false;
- } else if(!td->isCompleteOrError()) {
- QDeclarativeError error;
- error.setDescription(QLatin1String("QDeclarativeDomDocument supports local types only"));
- d->errors << error;
- td->release();
- return false;
- }
-
- for (int i = 0; i < td->parser().imports().size(); ++i) {
- QDeclarativeScriptParser::Import parserImport = td->parser().imports().at(i);
- QDeclarativeDomImport domImport;
- domImport.d->type = static_cast<QDeclarativeDomImportPrivate::Type>(parserImport.type);
- domImport.d->uri = parserImport.uri;
- domImport.d->qualifier = parserImport.qualifier;
- domImport.d->version = parserImport.version;
- d->imports += domImport;
- }
-
- if (td->parser().tree()) {
- d->root = td->parser().tree();
- d->root->addref();
- }
-
- td->release();
- return true;
-}
-
-/*!
- Returns the last load errors. The load errors will be reset after a
- successful call to load().
-
- \sa load()
-*/
-QList<QDeclarativeError> QDeclarativeDomDocument::errors() const
-{
- return d->errors;
-}
-
-/*!
- Returns the document's root object, or an invalid QDeclarativeDomObject if the
- document has no root.
-
- In the sample QML below, the root object will be the QDeclarativeItem type.
- \qml
-Item {
- Text {
- text: "Hello World"
- }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomDocument::rootObject() const
-{
- QDeclarativeDomObject rv;
- rv.d->object = d->root;
- if (rv.d->object) rv.d->object->addref();
- return rv;
-}
-
-QDeclarativeDomPropertyPrivate::QDeclarativeDomPropertyPrivate()
-: property(0)
-{
-}
-
-QDeclarativeDomPropertyPrivate::~QDeclarativeDomPropertyPrivate()
-{
- if (property) property->release();
-}
-
-QDeclarativeDomDynamicPropertyPrivate::QDeclarativeDomDynamicPropertyPrivate():
- valid(false)
-{
-}
-
-QDeclarativeDomDynamicPropertyPrivate::~QDeclarativeDomDynamicPropertyPrivate()
-{
- if (valid && property.defaultValue) property.defaultValue->release();
-}
-
-/*!
- \class QDeclarativeDomProperty
- \internal
- \brief The QDeclarativeDomProperty class represents one property assignment in the
- QML DOM tree
-
- Properties in QML can be assigned QML \l {QDeclarativeDomValue}{values}.
-
- \sa QDeclarativeDomObject
-*/
-
-/*!
- Construct an invalid QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty::QDeclarativeDomProperty()
-: d(new QDeclarativeDomPropertyPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty::QDeclarativeDomProperty(const QDeclarativeDomProperty &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty::~QDeclarativeDomProperty()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty &QDeclarativeDomProperty::operator=(const QDeclarativeDomProperty &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns true if this is a valid QDeclarativeDomProperty, false otherwise.
-*/
-bool QDeclarativeDomProperty::isValid() const
-{
- return d->property != 0;
-}
-
-
-/*!
- Return the name of this property.
-
- \qml
-Text {
- x: 10
- y: 10
- font.bold: true
-}
- \endqml
-
- As illustrated above, a property name can be a simple string, such as "x" or
- "y", or a more complex "dot property", such as "font.bold". In both cases
- the full name is returned ("x", "y" and "font.bold") by this method.
-
- For dot properties, a split version of the name can be accessed by calling
- QDeclarativeDomProperty::propertyNameParts().
-
- \sa QDeclarativeDomProperty::propertyNameParts()
-*/
-QByteArray QDeclarativeDomProperty::propertyName() const
-{
- return d->propertyName;
-}
-
-/*!
- Return the name of this property, split into multiple parts in the case
- of dot properties.
-
- \qml
-Text {
- x: 10
- y: 10
- font.bold: true
-}
- \endqml
-
- For each of the properties shown above, this method would return ("x"),
- ("y") and ("font", "bold").
-
- \sa QDeclarativeDomProperty::propertyName()
-*/
-QList<QByteArray> QDeclarativeDomProperty::propertyNameParts() const
-{
- if (d->propertyName.isEmpty()) return QList<QByteArray>();
- else return d->propertyName.split('.');
-}
-
-/*!
- Return true if this property is used as a default property in the QML
- document.
-
- \code
-<Text text="hello"/>
-<Text>hello</Text>
- \endcode
-
- The above two examples return the same DOM tree, except that the second has
- the default property flag set on the text property. Observe that whether
- or not a property has isDefaultProperty set is determined by how the
- property is used, and not only by whether the property is the types default
- property.
-*/
-bool QDeclarativeDomProperty::isDefaultProperty() const
-{
- return d->property && d->property->isDefault;
-}
-
-/*!
- Returns the QDeclarativeDomValue that is assigned to this property, or an invalid
- QDeclarativeDomValue if no value is assigned.
-*/
-QDeclarativeDomValue QDeclarativeDomProperty::value() const
-{
- QDeclarativeDomValue rv;
- if (d->property) {
- rv.d->property = d->property;
- if (d->property->values.count())
- rv.d->value = d->property->values.at(0);
- else
- rv.d->value = d->property->onValues.at(0);
- rv.d->property->addref();
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns the position in the input data where the property ID startd, or -1 if
- the property is invalid.
-*/
-int QDeclarativeDomProperty::position() const
-{
- if (d && d->property) {
- return d->property->location.range.offset;
- } else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the property ID started upto
- the end of it, or -1 if the property is invalid.
-*/
-int QDeclarativeDomProperty::length() const
-{
- if (d && d->property)
- return d->property->location.range.length;
- else
- return -1;
-}
-
-/*!
- Construct an invalid QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty::QDeclarativeDomDynamicProperty():
- d(new QDeclarativeDomDynamicPropertyPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty::QDeclarativeDomDynamicProperty(const QDeclarativeDomDynamicProperty &other):
- d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty::~QDeclarativeDomDynamicProperty()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomDynamicProperty.
-*/
-QDeclarativeDomDynamicProperty &QDeclarativeDomDynamicProperty::operator=(const QDeclarativeDomDynamicProperty &other)
-{
- d = other.d;
- return *this;
-}
-
-bool QDeclarativeDomDynamicProperty::isValid() const
-{
- return d && d->valid;
-}
-
-/*!
- Return the name of this dynamic property.
-
- \qml
-Item {
- property int count: 10;
-}
- \endqml
-
- As illustrated above, a dynamic property name can have a name and a
- default value ("10").
-*/
-QByteArray QDeclarativeDomDynamicProperty::propertyName() const
-{
- if (isValid())
- return d->property.name;
- else
- return QByteArray();
-}
-
-/*!
- Returns the type of the dynamic property. Note that when the property is an
- alias property, this will return -1. Use QDeclarativeDomProperty::isAlias() to check
- if the property is an alias.
-*/
-int QDeclarativeDomDynamicProperty::propertyType() const
-{
- if (isValid()) {
- switch (d->property.type) {
- case QDeclarativeParser::Object::DynamicProperty::Bool:
- return QMetaType::type("bool");
-
- case QDeclarativeParser::Object::DynamicProperty::Color:
- return QMetaType::type("QColor");
-
- case QDeclarativeParser::Object::DynamicProperty::Time:
- return QMetaType::type("QTime");
-
- case QDeclarativeParser::Object::DynamicProperty::Date:
- return QMetaType::type("QDate");
-
- case QDeclarativeParser::Object::DynamicProperty::DateTime:
- return QMetaType::type("QDateTime");
-
- case QDeclarativeParser::Object::DynamicProperty::Int:
- return QMetaType::type("int");
-
- case QDeclarativeParser::Object::DynamicProperty::Real:
- return sizeof(qreal) == sizeof(double) ? QMetaType::type("double") : QMetaType::type("float");
-
- case QDeclarativeParser::Object::DynamicProperty::String:
- return QMetaType::type("QString");
-
- case QDeclarativeParser::Object::DynamicProperty::Url:
- return QMetaType::type("QUrl");
-
- case QDeclarativeParser::Object::DynamicProperty::Variant:
- return QMetaType::type("QVariant");
-
- default:
- break;
- }
- }
-
- return -1;
-}
-
-QByteArray QDeclarativeDomDynamicProperty::propertyTypeName() const
-{
- if (isValid())
- return d->property.customType;
-
- return QByteArray();
-}
-
-/*!
- Return true if this property is used as a default property in the QML
- document.
-
- \code
-<Text text="hello"/>
-<Text>hello</Text>
- \endcode
-
- The above two examples return the same DOM tree, except that the second has
- the default property flag set on the text property. Observe that whether
- or not a property has isDefaultProperty set is determined by how the
- property is used, and not only by whether the property is the types default
- property.
-*/
-bool QDeclarativeDomDynamicProperty::isDefaultProperty() const
-{
- if (isValid())
- return d->property.isDefaultProperty;
- else
- return false;
-}
-
-/*!
- Returns the default value as a QDeclarativeDomProperty.
-*/
-QDeclarativeDomProperty QDeclarativeDomDynamicProperty::defaultValue() const
-{
- QDeclarativeDomProperty rp;
-
- if (isValid() && d->property.defaultValue) {
- rp.d->property = d->property.defaultValue;
- rp.d->propertyName = propertyName();
- rp.d->property->addref();
- }
-
- return rp;
-}
-
-/*!
- Returns true if this dynamic property is an alias for another property,
- false otherwise.
-*/
-bool QDeclarativeDomDynamicProperty::isAlias() const
-{
- if (isValid())
- return d->property.type == QDeclarativeParser::Object::DynamicProperty::Alias;
- else
- return false;
-}
-
-/*!
- Returns the position in the input data where the property ID startd, or 0 if
- the property is invalid.
-*/
-int QDeclarativeDomDynamicProperty::position() const
-{
- if (isValid()) {
- return d->property.location.range.offset;
- } else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the property ID started upto
- the end of it, or 0 if the property is invalid.
-*/
-int QDeclarativeDomDynamicProperty::length() const
-{
- if (isValid())
- return d->property.location.range.length;
- else
- return -1;
-}
-
-QDeclarativeDomObjectPrivate::QDeclarativeDomObjectPrivate()
-: object(0)
-{
-}
-
-QDeclarativeDomObjectPrivate::~QDeclarativeDomObjectPrivate()
-{
- if (object) object->release();
-}
-
-QDeclarativeDomObjectPrivate::Properties
-QDeclarativeDomObjectPrivate::properties() const
-{
- Properties rv;
-
- for (QHash<QByteArray, QDeclarativeParser::Property *>::ConstIterator iter =
- object->properties.begin();
- iter != object->properties.end();
- ++iter) {
-
- rv << properties(*iter);
-
- }
- return rv;
-}
-
-QDeclarativeDomObjectPrivate::Properties
-QDeclarativeDomObjectPrivate::properties(QDeclarativeParser::Property *property) const
-{
- Properties rv;
-
- if (property->value) {
-
- for (QHash<QByteArray, QDeclarativeParser::Property *>::ConstIterator iter =
- property->value->properties.begin();
- iter != property->value->properties.end();
- ++iter) {
-
- rv << properties(*iter);
-
- }
-
- QByteArray name(property->name + '.');
- for (Properties::Iterator iter = rv.begin(); iter != rv.end(); ++iter)
- iter->second.prepend(name);
-
- } else {
- rv << qMakePair(property, property->name);
- }
-
- return rv;
-}
-
-/*!
- \class QDeclarativeDomObject
- \internal
- \brief The QDeclarativeDomObject class represents an object instantiation.
-
- Each object instantiated in a QML file has a corresponding QDeclarativeDomObject
- node in the QML DOM.
-
- In addition to the type information that determines the object to
- instantiate, QDeclarativeDomObject's also have a set of associated QDeclarativeDomProperty's.
- Each QDeclarativeDomProperty represents a QML property assignment on the instantiated
- object. For example,
-
- \qml
-QGraphicsWidget {
- opacity: 0.5
- size: "100x100"
-}
- \endqml
-
- describes a single QDeclarativeDomObject - "QGraphicsWidget" - with two properties,
- "opacity" and "size". Obviously QGraphicsWidget has many more properties than just
- these two, but the QML DOM representation only contains those assigned
- values (or bindings) in the QML file.
-*/
-
-/*!
- Construct an invalid QDeclarativeDomObject.
-*/
-QDeclarativeDomObject::QDeclarativeDomObject()
-: d(new QDeclarativeDomObjectPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomObject.
-*/
-QDeclarativeDomObject::QDeclarativeDomObject(const QDeclarativeDomObject &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomObject.
-*/
-QDeclarativeDomObject::~QDeclarativeDomObject()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomObject.
-*/
-QDeclarativeDomObject &QDeclarativeDomObject::operator=(const QDeclarativeDomObject &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns true if this is a valid QDeclarativeDomObject, false otherwise.
-*/
-bool QDeclarativeDomObject::isValid() const
-{
- return d->object != 0;
-}
-
-/*!
- Returns the fully-qualified type name of this object.
-
- For example, the type of this object would be "Qt/4.6/Rectangle".
- \qml
-Rectangle { }
- \endqml
-*/
-QByteArray QDeclarativeDomObject::objectType() const
-{
- if (d->object) return d->object->typeName;
- else return QByteArray();
-}
-
-/*!
- Returns the type name as referenced in the qml file.
-
- For example, the type of this object would be "Rectangle".
- \qml
-Rectangle { }
- \endqml
-*/
-QByteArray QDeclarativeDomObject::objectClassName() const
-{
- if (d->object)
- return d->object->className;
- else
- return QByteArray();
-}
-
-int QDeclarativeDomObject::objectTypeMajorVersion() const
-{
- if (d->object)
- return d->object->majorVersion;
- else
- return -1;
-}
-
-int QDeclarativeDomObject::objectTypeMinorVersion() const
-{
- if (d->object)
- return d->object->minorVersion;
- else
- return -1;
-}
-
-/*!
- Returns the QML id assigned to this object, or an empty QByteArray if no id
- has been assigned.
-
- For example, the object id of this object would be "MyText".
- \qml
-Text { id: myText }
- \endqml
-*/
-QString QDeclarativeDomObject::objectId() const
-{
- if (d->object) {
- return d->object->id;
- } else {
- return QString();
- }
-}
-
-/*!
- Returns the list of assigned properties on this object.
-
- In the following example, "text" and "x" properties would be returned.
- \qml
-Text {
- text: "Hello world!"
- x: 100
-}
- \endqml
-*/
-QList<QDeclarativeDomProperty> QDeclarativeDomObject::properties() const
-{
- QList<QDeclarativeDomProperty> rv;
-
- if (!d->object || isComponent())
- return rv;
-
- QDeclarativeDomObjectPrivate::Properties properties = d->properties();
- for (int ii = 0; ii < properties.count(); ++ii) {
-
- QDeclarativeDomProperty domProperty;
- domProperty.d->property = properties.at(ii).first;
- domProperty.d->property->addref();
- domProperty.d->propertyName = properties.at(ii).second;
- rv << domProperty;
-
- }
-
- if (d->object->defaultProperty) {
- QDeclarativeDomProperty domProperty;
- domProperty.d->property = d->object->defaultProperty;
- domProperty.d->property->addref();
- domProperty.d->propertyName = d->object->defaultProperty->name;
- rv << domProperty;
- }
-
- return rv;
-}
-
-/*!
- Returns the object's \a name property if a value has been assigned to
- it, or an invalid QDeclarativeDomProperty otherwise.
-
- In the example below, \c {object.property("source")} would return a valid
- QDeclarativeDomProperty, and \c {object.property("tile")} an invalid QDeclarativeDomProperty.
-
- \qml
-Image { source: "sample.jpg" }
- \endqml
-*/
-QDeclarativeDomProperty QDeclarativeDomObject::property(const QByteArray &name) const
-{
- QList<QDeclarativeDomProperty> props = properties();
- for (int ii = 0; ii < props.count(); ++ii)
- if (props.at(ii).propertyName() == name)
- return props.at(ii);
- return QDeclarativeDomProperty();
-}
-
-QList<QDeclarativeDomDynamicProperty> QDeclarativeDomObject::dynamicProperties() const
-{
- QList<QDeclarativeDomDynamicProperty> properties;
-
- for (int i = 0; i < d->object->dynamicProperties.size(); ++i) {
- QDeclarativeDomDynamicProperty p;
- p.d = new QDeclarativeDomDynamicPropertyPrivate;
- p.d->property = d->object->dynamicProperties.at(i);
- p.d->valid = true;
-
- if (p.d->property.defaultValue)
- p.d->property.defaultValue->addref();
-
- properties.append(p);
- }
-
- return properties;
-}
-
-QDeclarativeDomDynamicProperty QDeclarativeDomObject::dynamicProperty(const QByteArray &name) const
-{
- QDeclarativeDomDynamicProperty p;
-
- if (!isValid())
- return p;
-
- for (int i = 0; i < d->object->dynamicProperties.size(); ++i) {
- if (d->object->dynamicProperties.at(i).name == name) {
- p.d = new QDeclarativeDomDynamicPropertyPrivate;
- p.d->property = d->object->dynamicProperties.at(i);
- if (p.d->property.defaultValue) p.d->property.defaultValue->addref();
- p.d->valid = true;
- }
- }
-
- return p;
-}
-
-/*!
- Returns true if this object is a custom type. Custom types are special
- types that allow embeddeding non-QML data, such as SVG or HTML data,
- directly into QML files.
-
- \note Currently this method will always return false, and is a placekeeper
- for future functionality.
-
- \sa QDeclarativeDomObject::customTypeData()
-*/
-bool QDeclarativeDomObject::isCustomType() const
-{
- return false;
-}
-
-/*!
- If this object represents a custom type, returns the data associated with
- the custom type, otherwise returns an empty QByteArray().
- QDeclarativeDomObject::isCustomType() can be used to check if this object represents
- a custom type.
-*/
-QByteArray QDeclarativeDomObject::customTypeData() const
-{
- return QByteArray();
-}
-
-/*!
- Returns true if this object is a sub-component object. Sub-component
- objects can be converted into QDeclarativeDomComponent instances by calling
- QDeclarativeDomObject::toComponent().
-
- \sa QDeclarativeDomObject::toComponent()
-*/
-bool QDeclarativeDomObject::isComponent() const
-{
- return (d->object && (d->object->typeName == "Qt/Component" || d->object->typeName == "QtQuick/Component"));
-}
-
-/*!
- Returns a QDeclarativeDomComponent for this object if it is a sub-component, or
- an invalid QDeclarativeDomComponent if not. QDeclarativeDomObject::isComponent() can be used
- to check if this object represents a sub-component.
-
- \sa QDeclarativeDomObject::isComponent()
-*/
-QDeclarativeDomComponent QDeclarativeDomObject::toComponent() const
-{
- QDeclarativeDomComponent rv;
- if (isComponent())
- rv.d = d;
- return rv;
-}
-
-/*!
- Returns the position in the input data where the property assignment started
-, or -1 if the property is invalid.
-*/
-int QDeclarativeDomObject::position() const
-{
- if (d && d->object)
- return d->object->location.range.offset;
- else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the property assignment star
-ted upto the end of it, or -1 if the property is invalid.
-*/
-int QDeclarativeDomObject::length() const
-{
- if (d && d->object)
- return d->object->location.range.length;
- else
- return -1;
-}
-
-// Returns the URL of the type, if it is an external type, or an empty URL if
-// not
-QUrl QDeclarativeDomObject::url() const
-{
- if (d && d->object)
- return d->object->url;
- else
- return QUrl();
-}
-
-QDeclarativeDomBasicValuePrivate::QDeclarativeDomBasicValuePrivate()
-: value(0)
-{
-}
-
-QDeclarativeDomBasicValuePrivate::~QDeclarativeDomBasicValuePrivate()
-{
- if (value) value->release();
-}
-
-/*!
- \class QDeclarativeDomValueLiteral
- \internal
- \brief The QDeclarativeDomValueLiteral class represents a literal value.
-
- A literal value is a simple value, written inline with the QML. In the
- example below, the "x", "y" and "color" properties are being assigned
- literal values.
-
- \qml
-Rectangle {
- x: 10
- y: 10
- color: "red"
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral::QDeclarativeDomValueLiteral():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral::QDeclarativeDomValueLiteral(const QDeclarativeDomValueLiteral &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral::~QDeclarativeDomValueLiteral()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueLiteral.
-*/
-QDeclarativeDomValueLiteral &QDeclarativeDomValueLiteral::operator=(const QDeclarativeDomValueLiteral &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the literal value.
-
- In the example below, the literal value will be the string "10".
- \qml
-Rectangle { x: 10 }
- \endqml
-*/
-QString QDeclarativeDomValueLiteral::literal() const
-{
- if (d->value) return d->value->primitive();
- else return QString();
-}
-
-/*!
- \class QDeclarativeDomValueBinding
- \internal
- \brief The QDeclarativeDomValueBinding class represents a property binding.
-
- A property binding is an ECMAScript expression assigned to a property. In
- the example below, the "x" property is being assigned a property binding.
-
- \qml
-Rectangle { x: Other.x }
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding::QDeclarativeDomValueBinding():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding::QDeclarativeDomValueBinding(const QDeclarativeDomValueBinding &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding::~QDeclarativeDomValueBinding()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueBinding.
-*/
-QDeclarativeDomValueBinding &QDeclarativeDomValueBinding::operator=(const QDeclarativeDomValueBinding &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the binding expression.
-
- In the example below, the string "Other.x" will be returned.
- \qml
-Rectangle { x: Other.x }
- \endqml
-*/
-QString QDeclarativeDomValueBinding::binding() const
-{
- if (d->value)
- return d->value->value.asScript();
- else
- return QString();
-}
-
-/*!
- \class QDeclarativeDomValueValueSource
- \internal
- \brief The QDeclarativeDomValueValueSource class represents a value source assignment value.
-
- In QML, value sources are special value generating types that may be
- assigned to properties. Value sources inherit the QDeclarativePropertyValueSource
- class. In the example below, the "x" property is being assigned the
- NumberAnimation value source.
-
- \qml
-Rectangle {
- x: NumberAnimation {
- from: 0
- to: 100
- loops: Animation.Infinite
- }
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource::QDeclarativeDomValueValueSource():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource::QDeclarativeDomValueValueSource(const QDeclarativeDomValueValueSource &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource::~QDeclarativeDomValueValueSource()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueValueSource.
-*/
-QDeclarativeDomValueValueSource &QDeclarativeDomValueValueSource::operator=(const QDeclarativeDomValueValueSource &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the value source object.
-
- In the example below, an object representing the NumberAnimation will be
- returned.
- \qml
-Rectangle {
- x: NumberAnimation {
- from: 0
- to: 100
- loops: Animation.Infinite
- }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomValueValueSource::object() const
-{
- QDeclarativeDomObject rv;
- if (d->value) {
- rv.d->object = d->value->object;
- rv.d->object->addref();
- }
- return rv;
-}
-
-/*!
- \class QDeclarativeDomValueValueInterceptor
- \internal
- \brief The QDeclarativeDomValueValueInterceptor class represents a value interceptor assignment value.
-
- In QML, value interceptor are special write-intercepting types that may be
- assigned to properties. Value interceptor inherit the QDeclarativePropertyValueInterceptor
- class. In the example below, the "x" property is being assigned the
- Behavior value interceptor.
-
- \qml
-Rectangle {
- Behavior on x { NumberAnimation { duration: 500 } }
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor::QDeclarativeDomValueValueInterceptor():
- d(new QDeclarativeDomBasicValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor::QDeclarativeDomValueValueInterceptor(const QDeclarativeDomValueValueInterceptor &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor::~QDeclarativeDomValueValueInterceptor()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValueValueInterceptor.
-*/
-QDeclarativeDomValueValueInterceptor &QDeclarativeDomValueValueInterceptor::operator=(const QDeclarativeDomValueValueInterceptor &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Return the value interceptor object.
-
- In the example below, an object representing the Behavior will be
- returned.
- \qml
-Rectangle {
- Behavior on x { NumberAnimation { duration: 500 } }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomValueValueInterceptor::object() const
-{
- QDeclarativeDomObject rv;
- if (d->value) {
- rv.d->object = d->value->object;
- rv.d->object->addref();
- }
- return rv;
-}
-
-QDeclarativeDomValuePrivate::QDeclarativeDomValuePrivate()
-: property(0), value(0)
-{
-}
-
-QDeclarativeDomValuePrivate::~QDeclarativeDomValuePrivate()
-{
- if (property) property->release();
- if (value) value->release();
-}
-
-/*!
- \class QDeclarativeDomValue
- \internal
- \brief The QDeclarativeDomValue class represents a generic Qml value.
-
- QDeclarativeDomValue's can be assigned to QML \l {QDeclarativeDomProperty}{properties}. In
- QML, properties can be assigned various different values, including basic
- literals, property bindings, property value sources, objects and lists of
- values. The QDeclarativeDomValue class allows a programmer to determine the specific
- value type being assigned and access more detailed information through a
- corresponding value type class.
-
- For example, in the following example,
-
- \qml
-Text {
- text: "Hello World!"
- y: Other.y
-}
- \endqml
-
- The text property is being assigned a literal, and the y property a property
- binding. To output the values assigned to the text and y properties in the
- above example from C++,
-
- \code
- QDeclarativeDomDocument document;
- QDeclarativeDomObject root = document.rootObject();
-
- QDeclarativeDomProperty text = root.property("text");
- if (text.value().isLiteral()) {
- QDeclarativeDomValueLiteral literal = text.value().toLiteral();
- qDebug() << literal.literal();
- }
-
- QDeclarativeDomProperty y = root.property("y");
- if (y.value().isBinding()) {
- QDeclarativeDomValueBinding binding = y.value().toBinding();
- qDebug() << binding.binding();
- }
- \endcode
-*/
-
-/*!
- Construct an invalid QDeclarativeDomValue.
-*/
-QDeclarativeDomValue::QDeclarativeDomValue()
-: d(new QDeclarativeDomValuePrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomValue.
-*/
-QDeclarativeDomValue::QDeclarativeDomValue(const QDeclarativeDomValue &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomValue
-*/
-QDeclarativeDomValue::~QDeclarativeDomValue()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomValue.
-*/
-QDeclarativeDomValue &QDeclarativeDomValue::operator=(const QDeclarativeDomValue &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- \enum QDeclarativeDomValue::Type
-
- The type of the QDeclarativeDomValue node.
-
- \value Invalid The QDeclarativeDomValue is invalid.
- \value Literal The QDeclarativeDomValue is a literal value assignment. Use QDeclarativeDomValue::toLiteral() to access the type instance.
- \value PropertyBinding The QDeclarativeDomValue is a property binding. Use QDeclarativeDomValue::toBinding() to access the type instance.
- \value ValueSource The QDeclarativeDomValue is a property value source. Use QDeclarativeDomValue::toValueSource() to access the type instance.
- \value ValueInterceptor The QDeclarativeDomValue is a property value interceptor. Use QDeclarativeDomValue::toValueInterceptor() to access the type instance.
- \value Object The QDeclarativeDomValue is an object assignment. Use QDeclarativeDomValue::toObject() to access the type instnace.
- \value List The QDeclarativeDomValue is a list of other values. Use QDeclarativeDomValue::toList() to access the type instance.
-*/
-
-/*!
- Returns the type of this QDeclarativeDomValue.
-*/
-QDeclarativeDomValue::Type QDeclarativeDomValue::type() const
-{
- if (d->property)
- if (QDeclarativeMetaType::isList(d->property->type) ||
- (d->property && (d->property->values.count() + d->property->onValues.count()) > 1))
- return List;
-
- QDeclarativeParser::Value *value = d->value;
- if (!value && !d->property)
- return Invalid;
-
- switch(value->type) {
- case QDeclarativeParser::Value::Unknown:
- return Invalid;
- case QDeclarativeParser::Value::Literal:
- return Literal;
- case QDeclarativeParser::Value::PropertyBinding:
- return PropertyBinding;
- case QDeclarativeParser::Value::ValueSource:
- return ValueSource;
- case QDeclarativeParser::Value::ValueInterceptor:
- return ValueInterceptor;
- case QDeclarativeParser::Value::CreatedObject:
- return Object;
- case QDeclarativeParser::Value::SignalObject:
- return Invalid;
- case QDeclarativeParser::Value::SignalExpression:
- return Literal;
- case QDeclarativeParser::Value::Id:
- return Literal;
- }
- return Invalid;
-}
-
-/*!
- Returns true if this is an invalid value, otherwise false.
-*/
-bool QDeclarativeDomValue::isInvalid() const
-{
- return type() == Invalid;
-}
-
-/*!
- Returns true if this is a literal value, otherwise false.
-*/
-bool QDeclarativeDomValue::isLiteral() const
-{
- return type() == Literal;
-}
-
-/*!
- Returns true if this is a property binding value, otherwise false.
-*/
-bool QDeclarativeDomValue::isBinding() const
-{
- return type() == PropertyBinding;
-}
-
-/*!
- Returns true if this is a value source value, otherwise false.
-*/
-bool QDeclarativeDomValue::isValueSource() const
-{
- return type() == ValueSource;
-}
-
-/*!
- Returns true if this is a value interceptor value, otherwise false.
-*/
-bool QDeclarativeDomValue::isValueInterceptor() const
-{
- return type() == ValueInterceptor;
-}
-
-/*!
- Returns true if this is an object value, otherwise false.
-*/
-bool QDeclarativeDomValue::isObject() const
-{
- return type() == Object;
-}
-
-/*!
- Returns true if this is a list value, otherwise false.
-*/
-bool QDeclarativeDomValue::isList() const
-{
- return type() == List;
-}
-
-/*!
- Returns a QDeclarativeDomValueLiteral if this value is a literal type, otherwise
- returns an invalid QDeclarativeDomValueLiteral.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueLiteral QDeclarativeDomValue::toLiteral() const
-{
- QDeclarativeDomValueLiteral rv;
- if (type() == Literal) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomValueBinding if this value is a property binding type,
- otherwise returns an invalid QDeclarativeDomValueBinding.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueBinding QDeclarativeDomValue::toBinding() const
-{
- QDeclarativeDomValueBinding rv;
- if (type() == PropertyBinding) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomValueValueSource if this value is a property value source
- type, otherwise returns an invalid QDeclarativeDomValueValueSource.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueValueSource QDeclarativeDomValue::toValueSource() const
-{
- QDeclarativeDomValueValueSource rv;
- if (type() == ValueSource) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomValueValueInterceptor if this value is a property value interceptor
- type, otherwise returns an invalid QDeclarativeDomValueValueInterceptor.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomValueValueInterceptor QDeclarativeDomValue::toValueInterceptor() const
-{
- QDeclarativeDomValueValueInterceptor rv;
- if (type() == ValueInterceptor) {
- rv.d->value = d->value;
- rv.d->value->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomObject if this value is an object assignment type, otherwise
- returns an invalid QDeclarativeDomObject.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomObject QDeclarativeDomValue::toObject() const
-{
- QDeclarativeDomObject rv;
- if (type() == Object) {
- rv.d->object = d->value->object;
- rv.d->object->addref();
- }
- return rv;
-}
-
-/*!
- Returns a QDeclarativeDomList if this value is a list type, otherwise returns an
- invalid QDeclarativeDomList.
-
- \sa QDeclarativeDomValue::type()
-*/
-QDeclarativeDomList QDeclarativeDomValue::toList() const
-{
- QDeclarativeDomList rv;
- if (type() == List) {
- rv.d = d;
- }
- return rv;
-}
-
-/*!
- Returns the position in the input data where the property value startd, or -1
- if the value is invalid.
-*/
-int QDeclarativeDomValue::position() const
-{
- if (type() == Invalid)
- return -1;
- else
- return d->value->location.range.offset;
-}
-
-/*!
- Returns the length in the input data from where the property value started u
-pto the end of it, or -1 if the value is invalid.
-*/
-int QDeclarativeDomValue::length() const
-{
- if (type() == Invalid)
- return -1;
- else
- return d->value->location.range.length;
-}
-
-/*!
- \class QDeclarativeDomList
- \internal
- \brief The QDeclarativeDomList class represents a list of values assigned to a QML property.
-
- Lists of values can be assigned to properties. For example, the following
- example assigns multiple objects to Item's "children" property
- \qml
-Item {
- children: [
- Text { },
- Rectangle { }
- ]
-}
- \endqml
-
- Lists can also be implicitly created by assigning multiple
- \l {QDeclarativeDomValueValueSource}{value sources} or constants to a property.
- \qml
-Item {
- x: 10
- x: NumberAnimation {
- running: false
- from: 0
- to: 100
- }
-}
- \endqml
-*/
-
-/*!
- Construct an empty QDeclarativeDomList.
-*/
-QDeclarativeDomList::QDeclarativeDomList()
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomList.
-*/
-QDeclarativeDomList::QDeclarativeDomList(const QDeclarativeDomList &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomList.
-*/
-QDeclarativeDomList::~QDeclarativeDomList()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomList.
-*/
-QDeclarativeDomList &QDeclarativeDomList::operator=(const QDeclarativeDomList &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns the list of QDeclarativeDomValue's.
-*/
-QList<QDeclarativeDomValue> QDeclarativeDomList::values() const
-{
- QList<QDeclarativeDomValue> rv;
- if (!d->property)
- return rv;
-
- for (int ii = 0; ii < d->property->values.count(); ++ii) {
- QDeclarativeDomValue v;
- v.d->value = d->property->values.at(ii);
- v.d->value->addref();
- rv << v;
- }
-
- for (int ii = 0; ii < d->property->onValues.count(); ++ii) {
- QDeclarativeDomValue v;
- v.d->value = d->property->onValues.at(ii);
- v.d->value->addref();
- rv << v;
- }
-
- return rv;
-}
-
-/*!
- Returns the position in the input data where the list started, or -1 if
- the property is invalid.
-*/
-int QDeclarativeDomList::position() const
-{
- if (d && d->property) {
- return d->property->listValueRange.offset;
- } else
- return -1;
-}
-
-/*!
- Returns the length in the input data from where the list started upto
- the end of it, or 0 if the property is invalid.
-*/
-int QDeclarativeDomList::length() const
-{
- if (d && d->property)
- return d->property->listValueRange.length;
- else
- return -1;
-}
-
-/*!
- Returns a list of positions of the commas in the QML file.
-*/
-QList<int> QDeclarativeDomList:: commaPositions() const
-{
- if (d && d->property)
- return d->property->listCommaPositions;
- else
- return QList<int>();
-}
-
-/*!
- \class QDeclarativeDomComponent
- \internal
- \brief The QDeclarativeDomComponent class represents sub-component within a QML document.
-
- Sub-components are QDeclarativeComponents defined within a QML document. The
- following example shows the definition of a sub-component with the id
- "listDelegate".
-
- \qml
-Item {
- Component {
- id: listDelegate
- Text {
- text: modelData.text
- }
- }
-}
- \endqml
-
- Like QDeclarativeDomDocument's, components contain a single root object.
-*/
-
-/*!
- Construct an empty QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent::QDeclarativeDomComponent()
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent::QDeclarativeDomComponent(const QDeclarativeDomComponent &other)
-: QDeclarativeDomObject(other)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent::~QDeclarativeDomComponent()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomComponent.
-*/
-QDeclarativeDomComponent &QDeclarativeDomComponent::operator=(const QDeclarativeDomComponent &other)
-{
- static_cast<QDeclarativeDomObject &>(*this) = other;
- return *this;
-}
-
-/*!
- Returns the component's root object.
-
- In the example below, the root object is the "Text" object.
- \qml
-Item {
- Component {
- id: listDelegate
- Text {
- text: modelData.text
- }
- }
-}
- \endqml
-*/
-QDeclarativeDomObject QDeclarativeDomComponent::componentRoot() const
-{
- QDeclarativeDomObject rv;
- if (d->object) {
- QDeclarativeParser::Object *obj = 0;
- if (d->object->defaultProperty &&
- d->object->defaultProperty->values.count() == 1 &&
- d->object->defaultProperty->values.at(0)->object)
- obj = d->object->defaultProperty->values.at(0)->object;
-
- if (obj) {
- rv.d->object = obj;
- rv.d->object->addref();
- }
- }
-
- return rv;
-}
-
-QDeclarativeDomImportPrivate::QDeclarativeDomImportPrivate()
-: type(File)
-{
-}
-
-QDeclarativeDomImportPrivate::~QDeclarativeDomImportPrivate()
-{
-}
-
-/*!
- \class QDeclarativeDomImport
- \internal
- \brief The QDeclarativeDomImport class represents an import statement.
-*/
-
-/*!
- Construct an empty QDeclarativeDomImport.
-*/
-QDeclarativeDomImport::QDeclarativeDomImport()
-: d(new QDeclarativeDomImportPrivate)
-{
-}
-
-/*!
- Create a copy of \a other QDeclarativeDomImport.
-*/
-QDeclarativeDomImport::QDeclarativeDomImport(const QDeclarativeDomImport &other)
-: d(other.d)
-{
-}
-
-/*!
- Destroy the QDeclarativeDomImport.
-*/
-QDeclarativeDomImport::~QDeclarativeDomImport()
-{
-}
-
-/*!
- Assign \a other to this QDeclarativeDomImport.
-*/
-QDeclarativeDomImport &QDeclarativeDomImport::operator=(const QDeclarativeDomImport &other)
-{
- d = other.d;
- return *this;
-}
-
-/*!
- Returns the type of the import.
- */
-QDeclarativeDomImport::Type QDeclarativeDomImport::type() const
-{
- return static_cast<QDeclarativeDomImport::Type>(d->type);
-}
-
-/*!
- Returns the URI of the import (e.g. 'subdir' or 'com.nokia.Qt')
- */
-QString QDeclarativeDomImport::uri() const
-{
- return d->uri;
-}
-
-/*!
- Returns the version specified by the import. An empty string if no version was specified.
- */
-QString QDeclarativeDomImport::version() const
-{
- return d->version;
-}
-
-/*!
- Returns the (optional) qualifier string (the token following the 'as' keyword) of the import.
- */
-QString QDeclarativeDomImport::qualifier() const
-{
- return d->qualifier;
-}
-
-QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativedom_p.h b/src/declarative/qml/qdeclarativedom_p.h
deleted file mode 100644
index 64300d47e7..0000000000
--- a/src/declarative/qml/qdeclarativedom_p.h
+++ /dev/null
@@ -1,362 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDECLARATIVEDOM_P_H
-#define QDECLARATIVEDOM_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 "qdeclarativeerror.h"
-
-#include <QtCore/qlist.h>
-#include <QtCore/qshareddata.h>
-
-#include <private/qdeclarativeglobal_p.h>
-
-QT_BEGIN_HEADER
-
-QT_BEGIN_NAMESPACE
-
-QT_MODULE(Declarative)
-
-class QString;
-class QByteArray;
-class QDeclarativeDomObject;
-class QDeclarativeDomList;
-class QDeclarativeDomValue;
-class QDeclarativeEngine;
-class QDeclarativeDomComponent;
-class QDeclarativeDomImport;
-class QIODevice;
-
-class QDeclarativeDomDocumentPrivate;
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomDocument
-{
-public:
- QDeclarativeDomDocument();
- QDeclarativeDomDocument(const QDeclarativeDomDocument &);
- ~QDeclarativeDomDocument();
- QDeclarativeDomDocument &operator=(const QDeclarativeDomDocument &);
-
- QList<QDeclarativeDomImport> imports() const;
-
- QList<QDeclarativeError> errors() const;
- bool load(QDeclarativeEngine *, const QByteArray &, const QUrl & = QUrl());
-
- QDeclarativeDomObject rootObject() const;
-
-private:
- QSharedDataPointer<QDeclarativeDomDocumentPrivate> d;
-};
-
-class QDeclarativeDomPropertyPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomProperty
-{
-public:
- QDeclarativeDomProperty();
- QDeclarativeDomProperty(const QDeclarativeDomProperty &);
- ~QDeclarativeDomProperty();
- QDeclarativeDomProperty &operator=(const QDeclarativeDomProperty &);
-
- bool isValid() const;
-
- QByteArray propertyName() const;
- QList<QByteArray> propertyNameParts() const;
-
- bool isDefaultProperty() const;
-
- QDeclarativeDomValue value() const;
-
- int position() const;
- int length() const;
-
-private:
- friend class QDeclarativeDomObject;
- friend class QDeclarativeDomDynamicProperty;
- QSharedDataPointer<QDeclarativeDomPropertyPrivate> d;
-};
-
-class QDeclarativeDomDynamicPropertyPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomDynamicProperty
-{
-public:
- QDeclarativeDomDynamicProperty();
- QDeclarativeDomDynamicProperty(const QDeclarativeDomDynamicProperty &);
- ~QDeclarativeDomDynamicProperty();
- QDeclarativeDomDynamicProperty &operator=(const QDeclarativeDomDynamicProperty &);
-
- bool isValid() const;
-
- QByteArray propertyName() const;
- int propertyType() const;
- QByteArray propertyTypeName() const;
-
- bool isDefaultProperty() const;
- QDeclarativeDomProperty defaultValue() const;
-
- bool isAlias() const;
-
- int position() const;
- int length() const;
-
-private:
- friend class QDeclarativeDomObject;
- QSharedDataPointer<QDeclarativeDomDynamicPropertyPrivate> d;
-};
-
-class QDeclarativeDomObjectPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomObject
-{
-public:
- QDeclarativeDomObject();
- QDeclarativeDomObject(const QDeclarativeDomObject &);
- ~QDeclarativeDomObject();
- QDeclarativeDomObject &operator=(const QDeclarativeDomObject &);
-
- bool isValid() const;
-
- QByteArray objectType() const;
- QByteArray objectClassName() const;
-
- int objectTypeMajorVersion() const;
- int objectTypeMinorVersion() const;
-
- QString objectId() const;
-
- QList<QDeclarativeDomProperty> properties() const;
- QDeclarativeDomProperty property(const QByteArray &) const;
-
- QList<QDeclarativeDomDynamicProperty> dynamicProperties() const;
- QDeclarativeDomDynamicProperty dynamicProperty(const QByteArray &) const;
-
- bool isCustomType() const;
- QByteArray customTypeData() const;
-
- bool isComponent() const;
- QDeclarativeDomComponent toComponent() const;
-
- int position() const;
- int length() const;
-
- QUrl url() const;
-private:
- friend class QDeclarativeDomDocument;
- friend class QDeclarativeDomComponent;
- friend class QDeclarativeDomValue;
- friend class QDeclarativeDomValueValueSource;
- friend class QDeclarativeDomValueValueInterceptor;
- QSharedDataPointer<QDeclarativeDomObjectPrivate> d;
-};
-
-class QDeclarativeDomValuePrivate;
-class QDeclarativeDomBasicValuePrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueLiteral
-{
-public:
- QDeclarativeDomValueLiteral();
- QDeclarativeDomValueLiteral(const QDeclarativeDomValueLiteral &);
- ~QDeclarativeDomValueLiteral();
- QDeclarativeDomValueLiteral &operator=(const QDeclarativeDomValueLiteral &);
-
- QString literal() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueBinding
-{
-public:
- QDeclarativeDomValueBinding();
- QDeclarativeDomValueBinding(const QDeclarativeDomValueBinding &);
- ~QDeclarativeDomValueBinding();
- QDeclarativeDomValueBinding &operator=(const QDeclarativeDomValueBinding &);
-
- QString binding() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueValueSource
-{
-public:
- QDeclarativeDomValueValueSource();
- QDeclarativeDomValueValueSource(const QDeclarativeDomValueValueSource &);
- ~QDeclarativeDomValueValueSource();
- QDeclarativeDomValueValueSource &operator=(const QDeclarativeDomValueValueSource &);
-
- QDeclarativeDomObject object() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueValueInterceptor
-{
-public:
- QDeclarativeDomValueValueInterceptor();
- QDeclarativeDomValueValueInterceptor(const QDeclarativeDomValueValueInterceptor &);
- ~QDeclarativeDomValueValueInterceptor();
- QDeclarativeDomValueValueInterceptor &operator=(const QDeclarativeDomValueValueInterceptor &);
-
- QDeclarativeDomObject object() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d;
-};
-
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomComponent : public QDeclarativeDomObject
-{
-public:
- QDeclarativeDomComponent();
- QDeclarativeDomComponent(const QDeclarativeDomComponent &);
- ~QDeclarativeDomComponent();
- QDeclarativeDomComponent &operator=(const QDeclarativeDomComponent &);
-
- QDeclarativeDomObject componentRoot() const;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValue
-{
-public:
- enum Type {
- Invalid,
- Literal,
- PropertyBinding,
- ValueSource,
- ValueInterceptor,
- Object,
- List
- };
-
- QDeclarativeDomValue();
- QDeclarativeDomValue(const QDeclarativeDomValue &);
- ~QDeclarativeDomValue();
- QDeclarativeDomValue &operator=(const QDeclarativeDomValue &);
-
- Type type() const;
-
- bool isInvalid() const;
- bool isLiteral() const;
- bool isBinding() const;
- bool isValueSource() const;
- bool isValueInterceptor() const;
- bool isObject() const;
- bool isList() const;
-
- QDeclarativeDomValueLiteral toLiteral() const;
- QDeclarativeDomValueBinding toBinding() const;
- QDeclarativeDomValueValueSource toValueSource() const;
- QDeclarativeDomValueValueInterceptor toValueInterceptor() const;
- QDeclarativeDomObject toObject() const;
- QDeclarativeDomList toList() const;
-
- int position() const;
- int length() const;
-
-private:
- friend class QDeclarativeDomProperty;
- friend class QDeclarativeDomList;
- QSharedDataPointer<QDeclarativeDomValuePrivate> d;
-};
-
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomList
-{
-public:
- QDeclarativeDomList();
- QDeclarativeDomList(const QDeclarativeDomList &);
- ~QDeclarativeDomList();
- QDeclarativeDomList &operator=(const QDeclarativeDomList &);
-
- QList<QDeclarativeDomValue> values() const;
-
- int position() const;
- int length() const;
-
- QList<int> commaPositions() const;
-
-private:
- friend class QDeclarativeDomValue;
- QSharedDataPointer<QDeclarativeDomValuePrivate> d;
-};
-
-class QDeclarativeDomImportPrivate;
-class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomImport
-{
-public:
- enum Type { Library, File };
-
- QDeclarativeDomImport();
- QDeclarativeDomImport(const QDeclarativeDomImport &);
- ~QDeclarativeDomImport();
- QDeclarativeDomImport &operator=(const QDeclarativeDomImport &);
-
- Type type() const;
- QString uri() const;
- QString version() const;
- QString qualifier() const;
-
-private:
- friend class QDeclarativeDomDocument;
- QSharedDataPointer<QDeclarativeDomImportPrivate> d;
-};
-
-QT_END_NAMESPACE
-
-QT_END_HEADER
-
-#endif // QDECLARATIVEDOM_P_H
diff --git a/src/declarative/qml/qdeclarativedom_p_p.h b/src/declarative/qml/qdeclarativedom_p_p.h
deleted file mode 100644
index 7ce99ec74d..0000000000
--- a/src/declarative/qml/qdeclarativedom_p_p.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDECLARATIVEDOM_P_P_H
-#define QDECLARATIVEDOM_P_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/qdeclarativeparser_p.h"
-
-#include <QtCore/QtGlobal>
-
-QT_BEGIN_NAMESPACE
-
-class QDeclarativeDomDocumentPrivate : public QSharedData
-{
-public:
- QDeclarativeDomDocumentPrivate();
- QDeclarativeDomDocumentPrivate(const QDeclarativeDomDocumentPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomDocumentPrivate();
-
- QList<QDeclarativeError> errors;
- QList<QDeclarativeDomImport> imports;
- QDeclarativeParser::Object *root;
- QList<int> automaticSemicolonOffsets;
-};
-
-class QDeclarativeDomObjectPrivate : public QSharedData
-{
-public:
- QDeclarativeDomObjectPrivate();
- QDeclarativeDomObjectPrivate(const QDeclarativeDomObjectPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomObjectPrivate();
-
- typedef QList<QPair<QDeclarativeParser::Property *, QByteArray> > Properties;
- Properties properties() const;
- Properties properties(QDeclarativeParser::Property *) const;
-
- QDeclarativeParser::Object *object;
-};
-
-class QDeclarativeDomPropertyPrivate : public QSharedData
-{
-public:
- QDeclarativeDomPropertyPrivate();
- QDeclarativeDomPropertyPrivate(const QDeclarativeDomPropertyPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomPropertyPrivate();
-
- QByteArray propertyName;
- QDeclarativeParser::Property *property;
-};
-
-class QDeclarativeDomDynamicPropertyPrivate : public QSharedData
-{
-public:
- QDeclarativeDomDynamicPropertyPrivate();
- QDeclarativeDomDynamicPropertyPrivate(const QDeclarativeDomDynamicPropertyPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomDynamicPropertyPrivate();
-
- bool valid;
- QDeclarativeParser::Object::DynamicProperty property;
-};
-
-class QDeclarativeDomValuePrivate : public QSharedData
-{
-public:
- QDeclarativeDomValuePrivate();
- QDeclarativeDomValuePrivate(const QDeclarativeDomValuePrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomValuePrivate();
-
- QDeclarativeParser::Property *property;
- QDeclarativeParser::Value *value;
-};
-
-class QDeclarativeDomBasicValuePrivate : public QSharedData
-{
-public:
- QDeclarativeDomBasicValuePrivate();
- QDeclarativeDomBasicValuePrivate(const QDeclarativeDomBasicValuePrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomBasicValuePrivate();
-
- QDeclarativeParser::Value *value;
-};
-
-class QDeclarativeDomImportPrivate : public QSharedData
-{
-public:
- QDeclarativeDomImportPrivate();
- QDeclarativeDomImportPrivate(const QDeclarativeDomImportPrivate &o)
- : QSharedData(o) { qFatal("Not impl"); }
- ~QDeclarativeDomImportPrivate();
-
- enum Type { Library, File };
-
- Type type;
- QString uri;
- QString version;
- QString qualifier;
-};
-
-QT_END_NAMESPACE
-
-#endif // QDECLARATIVEDOM_P_P_H
-
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index 9fde18c81c..b30b4cfb55 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -55,6 +55,7 @@
#include "private/qdeclarativestringconverters_p.h"
#include "private/qdeclarativexmlhttprequest_p.h"
#include "private/qdeclarativesqldatabase_p.h"
+#include "private/qdeclarativescarceresourcescriptclass_p.h"
#include "private/qdeclarativetypenamescriptclass_p.h"
#include "private/qdeclarativelistscriptclass_p.h"
#include "qdeclarativescriptstring.h"
@@ -103,6 +104,8 @@
#include <private/qdeclarativeitemsmodule_p.h>
#include <private/qdeclarativeutilmodule_p.h>
+#include <private/qsgitemsmodule_p.h>
+#include <qsgtexture.h>
#ifdef Q_OS_WIN // for %APPDATA%
#include <qt_windows.h>
@@ -349,13 +352,15 @@ QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
objectClass(0), valueTypeClass(0), globalClass(0), cleanup(0), erroredBindings(0),
inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttached(0),
inBeginCreate(false), networkAccessManager(0), networkAccessManagerFactory(0),
- typeLoader(e), importDatabase(e), uniqueId(1)
+ scarceResources(0), scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
+ sgContext(0)
{
if (!qt_QmlQtModule_registered) {
qt_QmlQtModule_registered = true;
QDeclarativeItemModule::defineModule();
QDeclarativeUtilModule::defineModule();
QDeclarativeEnginePrivate::defineModule();
+ QSGItemsModule::defineModule();
QDeclarativeValueTypeFactory::registerValueTypes();
}
globalClass = new QDeclarativeGlobalScriptClass(&scriptEngine);
@@ -499,6 +504,8 @@ QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
contextClass = 0;
delete objectClass;
objectClass = 0;
+ delete scarceResourceClass;
+ scarceResourceClass = 0;
delete valueTypeClass;
valueTypeClass = 0;
delete typeNameClass;
@@ -514,7 +521,10 @@ QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
(*iter)->release();
for(QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
(*iter)->release();
-
+ for(QHash<QDeclarativeMetaType::ModuleApi, QDeclarativeMetaType::ModuleApiInstance *>::Iterator iter = moduleApiInstances.begin(); iter != moduleApiInstances.end(); ++iter) {
+ delete (*iter)->qobjectApi;
+ delete *iter;
+ }
}
void QDeclarativeEnginePrivate::clear(SimpleList<QDeclarativeAbstractBinding> &bvs)
@@ -571,6 +581,7 @@ void QDeclarativeEnginePrivate::init()
contextClass = new QDeclarativeContextScriptClass(q);
objectClass = new QDeclarativeObjectScriptClass(q);
+ scarceResourceClass = new QDeclarativeScarceResourceScriptClass(q);
valueTypeClass = new QDeclarativeValueTypeScriptClass(q);
typeNameClass = new QDeclarativeTypeNameScriptClass(q);
listClass = new QDeclarativeListScriptClass(q);
@@ -647,6 +658,22 @@ QDeclarativeEngine::~QDeclarativeEngine()
Q_D(QDeclarativeEngine);
if (d->isDebugging)
QDeclarativeEngineDebugServer::instance()->remEngine(this);
+
+ // if we are the parent of any of the qobject module api instances,
+ // we need to remove them from our internal list, in order to prevent
+ // a segfault in engine private dtor.
+ QList<QDeclarativeMetaType::ModuleApi> keys = d->moduleApiInstances.keys();
+ QObject *currQObjectApi = 0;
+ QDeclarativeMetaType::ModuleApiInstance *currInstance = 0;
+ foreach (const QDeclarativeMetaType::ModuleApi &key, keys) {
+ currInstance = d->moduleApiInstances.value(key);
+ currQObjectApi = currInstance->qobjectApi;
+ if (this->children().contains(currQObjectApi)) {
+ delete currQObjectApi;
+ delete currInstance;
+ d->moduleApiInstances.remove(key);
+ }
+ }
}
/*! \fn void QDeclarativeEngine::quit()
@@ -813,6 +840,18 @@ QDeclarativeImageProvider::ImageType QDeclarativeEnginePrivate::getImageProvider
return static_cast<QDeclarativeImageProvider::ImageType>(-1);
}
+QSGTexture *QDeclarativeEnginePrivate::getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
+{
+ QMutexLocker locker(&mutex);
+ QSharedPointer<QDeclarativeImageProvider> provider = imageProviders.value(url.host());
+ locker.unlock();
+ if (provider) {
+ QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
+ return provider->requestTexture(imageId, size, req_size);
+ }
+ return 0;
+}
+
QImage QDeclarativeEnginePrivate::getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
{
QMutexLocker locker(&mutex);
@@ -2056,7 +2095,9 @@ QScriptValue QDeclarativeEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine
QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &val)
{
- if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) {
+ if (variantIsScarceResource(val)) {
+ return scarceResourceClass->newScarceResource(val);
+ } else if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) {
QDeclarativeListReferencePrivate *p =
QDeclarativeListReferencePrivate::get((QDeclarativeListReference*)val.constData());
if (p->object) {
@@ -2085,11 +2126,69 @@ QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &v
}
}
+/*
+ If the variant is a scarce resource (consumes a large amount of memory, or
+ only a limited number of them can be held in memory at any given time without
+ exhausting supply for future use) we need to release the scarce resource
+ after evaluation of the javascript binding is complete.
+ */
+bool QDeclarativeEnginePrivate::variantIsScarceResource(const QVariant& val)
+{
+ if (val.type() == QVariant::Pixmap) {
+ return true;
+ } else if (val.type() == QVariant::Image) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ This function should be called prior to evaluation of any js expression,
+ so that scarce resources are not freed prematurely (eg, if there is a
+ nested javascript expression).
+ */
+void QDeclarativeEnginePrivate::referenceScarceResources()
+{
+ scarceResourcesRefCount += 1;
+}
+
+/*
+ This function should be called after evaluation of the js expression is
+ complete, and so the scarce resources may be freed safely.
+ */
+void QDeclarativeEnginePrivate::dereferenceScarceResources()
+{
+ Q_ASSERT(scarceResourcesRefCount > 0);
+ scarceResourcesRefCount -= 1;
+
+ // if the refcount is zero, then evaluation of the "top level"
+ // expression must have completed. We can safely release the
+ // scarce resources.
+ if (scarceResourcesRefCount == 0) {
+ // iterate through the list and release them all.
+ // note that the actual SRD is owned by the JS engine,
+ // so we cannot delete the SRD; but we can free the
+ // memory used by the variant in the SRD.
+ ScarceResourceData *srd = 0;
+ while (scarceResources) {
+ srd = scarceResources; // srd points to the "old" (current) head of the list
+ scarceResources = srd->next; // srd->next is the "new" head of the list
+ if (srd->next) srd->next->prev = &scarceResources; // newHead->prev = listptr.
+ srd->next = 0;
+ srd->prev = 0;
+ srd->releaseResource(); // release the old head node.
+ }
+ }
+}
+
QVariant QDeclarativeEnginePrivate::scriptValueToVariant(const QScriptValue &val, int hint)
{
QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val);
if (dc == objectClass)
return QVariant::fromValue(objectClass->toQObject(val));
+ else if (dc == scarceResourceClass)
+ return scarceResourceClass->toVariant(val);
else if (dc == valueTypeClass)
return valueTypeClass->toVariant(val);
else if (dc == contextClass)
@@ -2218,6 +2317,20 @@ void QDeclarativeEngine::setPluginPathList(const QStringList &paths)
Imports the plugin named \a filePath with the \a uri provided.
Returns true if the plugin was successfully imported; otherwise returns false.
+ 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 QDeclarativeExtensionPlugin interface.
+*/
+bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors)
+{
+ Q_D(QDeclarativeEngine);
+ return d->importDatabase.importPlugin(filePath, uri, errors);
+}
+
+/*!
+ Imports the plugin named \a filePath with the \a uri provided.
+ Returns true if the plugin was successfully imported; otherwise returns false.
+
On failure and if non-null, *\a errorString will be set to a message describing the failure.
The plugin has to be a Qt plugin which implements the QDeclarativeExtensionPlugin interface.
@@ -2225,7 +2338,18 @@ void QDeclarativeEngine::setPluginPathList(const QStringList &paths)
bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
{
Q_D(QDeclarativeEngine);
- return d->importDatabase.importPlugin(filePath, uri, errorString);
+ QList<QDeclarativeError> errors;
+ bool retn = d->importDatabase.importPlugin(filePath, uri, &errors);
+ if (!errors.isEmpty()) {
+ QString builtError;
+ for (int i = 0; i < errors.size(); ++i) {
+ builtError = QString(QLatin1String("%1\n %2"))
+ .arg(builtError)
+ .arg(errors.at(i).toString());
+ }
+ *errorString = builtError;
+ }
+ return retn;
}
/*!
diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h
index 631fc5ec57..8db3db8096 100644
--- a/src/declarative/qml/qdeclarativeengine.h
+++ b/src/declarative/qml/qdeclarativeengine.h
@@ -86,7 +86,8 @@ public:
void setPluginPathList(const QStringList &paths);
void addPluginPath(const QString& dir);
- bool importPlugin(const QString &filePath, const QString &uri, QString *errorString);
+ bool importPlugin(const QString &filePath, const QString &uri, QString *errorString); // XXX: Qt 5: Remove this function
+ bool importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors);
void setNetworkAccessManagerFactory(QDeclarativeNetworkAccessManagerFactory *);
QDeclarativeNetworkAccessManagerFactory *networkAccessManagerFactory() const;
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index 88b4e800f8..fadedf41dd 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -67,6 +67,7 @@
#include "private/qdeclarativeproperty_p.h"
#include "private/qdeclarativepropertycache_p.h"
#include "private/qdeclarativeobjectscriptclass_p.h"
+#include "private/qdeclarativescarceresourcescriptclass_p.h"
#include "private/qdeclarativecontextscriptclass_p.h"
#include "private/qdeclarativevaluetypescriptclass_p.h"
#include "private/qdeclarativemetatype_p.h"
@@ -93,6 +94,8 @@ class QDeclarativeExpression;
class QDeclarativeContextScriptClass;
class QDeclarativeImportDatabase;
class QDeclarativeObjectScriptClass;
+class QDeclarativeScarceResourceScriptClass;
+class ScarceResourceData;
class QDeclarativeTypeNameScriptClass;
class QDeclarativeValueTypeScriptClass;
class QScriptEngineDebugger;
@@ -110,6 +113,8 @@ class QDeclarativeDelayedError;
class QDeclarativeWorkerScriptEngine;
class QDeclarativeGlobalScriptClass;
class QDir;
+class QSGTexture;
+class QSGContext;
class QDeclarativeScriptEngine : public QScriptEngine
{
@@ -169,6 +174,7 @@ public:
QDeclarativeContextData *sharedContext;
QObject *sharedScope;
QDeclarativeObjectScriptClass *objectClass;
+ QDeclarativeScarceResourceScriptClass *scarceResourceClass;
QDeclarativeValueTypeScriptClass *valueTypeClass;
QDeclarativeTypeNameScriptClass *typeNameClass;
QDeclarativeListScriptClass *listClass;
@@ -233,9 +239,22 @@ public:
QHash<QString,QSharedPointer<QDeclarativeImageProvider> > imageProviders;
QDeclarativeImageProvider::ImageType getImageProviderType(const QUrl &url);
+ QSGTexture *getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
+ /*
+ A scarce resource (like a large pixmap or texture) will be cached in a
+ JavaScript wrapper object when accessed in a binding or other js expression.
+ We need some way to automatically release that scarce resource prior to normal
+ garbage collection (unless the user explicitly preserves the resource).
+ */
+ ScarceResourceData* scarceResources;
+ int scarceResourcesRefCount;
+ static bool variantIsScarceResource(const QVariant& val);
+ void referenceScarceResources();
+ void dereferenceScarceResources();
+
mutable QMutex mutex;
QDeclarativeTypeLoader typeLoader;
@@ -250,6 +269,8 @@ public:
QDeclarativeValueTypeFactory valueTypes;
+ QHash<QDeclarativeMetaType::ModuleApi, QDeclarativeMetaType::ModuleApiInstance *> moduleApiInstances;
+
QHash<const QMetaObject *, QDeclarativePropertyCache *> propertyCache;
QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *> typePropertyCache;
inline QDeclarativePropertyCache *cache(QObject *obj);
@@ -270,8 +291,6 @@ public:
QHash<int, int> m_qmlLists;
QHash<int, QDeclarativeCompiledData *> m_compositeTypes;
- QHash<QString, QScriptValue> m_sharedScriptImports;
-
QScriptValue scriptValueFromVariant(const QVariant &);
QVariant scriptValueToVariant(const QScriptValue &, int hint = QVariant::Invalid);
@@ -327,6 +346,8 @@ public:
static void defineModule();
static bool qml_debugging_enabled;
+
+ QSGContext *sgContext;
};
/*!
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index 7a85adaa6e..afd1be1025 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -630,7 +630,6 @@ QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope,
if (!expressionFunctionValid) {
QDeclarativeEngine *engine = context()->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
@@ -663,8 +662,10 @@ QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isU
}
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
-
- return ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >());
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
+ QVariant retn(ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >()));
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
+ return retn;
}
/*!
diff --git a/src/declarative/qml/qdeclarativeimageprovider.cpp b/src/declarative/qml/qdeclarativeimageprovider.cpp
index f111c201fa..c9b399cc32 100644
--- a/src/declarative/qml/qdeclarativeimageprovider.cpp
+++ b/src/declarative/qml/qdeclarativeimageprovider.cpp
@@ -159,6 +159,8 @@ public:
requestImage() method will be called for all image requests.
\value Pixmap The Image Provider provides QPixmap images. The
requestPixmap() method will be called for all image requests.
+ \value Texture The Image Provider provides QSGTextureProvider based images.
+ The requestTexture() method will be called for all image requests. \omitvalue
*/
/*!
@@ -243,5 +245,36 @@ QPixmap QDeclarativeImageProvider::requestPixmap(const QString &id, QSize *size,
return QPixmap();
}
+
+/*!
+ Implement this method to return the texture with \a id. The default
+ implementation returns 0.
+
+ The \a id is the requested image source, with the "image:" scheme and
+ provider identifier removed. For example, if the image \l{Image::}{source}
+ was "image://myprovider/icons/home", the given \a id would be "icons/home".
+
+ The \a requestedSize corresponds to the \l {Image::sourceSize} requested by
+ an Image element. If \a requestedSize is a valid size, the image
+ returned should be of that size.
+
+ In all cases, \a size must be set to the original size of the image. This
+ is used to set the \l {Item::}{width} and \l {Item::}{height} of the
+ relevant \l Image if these values have not been set explicitly.
+
+ \note this method may be called by multiple threads, so ensure the
+ implementation of this method is reentrant.
+*/
+
+QSGTexture *QDeclarativeImageProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(size);
+ Q_UNUSED(requestedSize);
+ if (d->type == Texture)
+ qWarning("ImageProvider supports Texture type but has not implemented requestTexture()");
+ return 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeimageprovider.h b/src/declarative/qml/qdeclarativeimageprovider.h
index 7f13fda85b..e5e80f227c 100644
--- a/src/declarative/qml/qdeclarativeimageprovider.h
+++ b/src/declarative/qml/qdeclarativeimageprovider.h
@@ -52,13 +52,15 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class QDeclarativeImageProviderPrivate;
+class QSGTexture;
class Q_DECLARATIVE_EXPORT QDeclarativeImageProvider
{
public:
enum ImageType {
Image,
- Pixmap
+ Pixmap,
+ Texture
};
QDeclarativeImageProvider(ImageType type);
@@ -68,6 +70,7 @@ public:
virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize);
virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize);
+ virtual QSGTexture *requestTexture(const QString &id, QSize *size, const QSize &requestedSize);
private:
QDeclarativeImageProviderPrivate *d;
diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp
index e8d593fd1a..c5abe2c75d 100644
--- a/src/declarative/qml/qdeclarativeimport.cpp
+++ b/src/declarative/qml/qdeclarativeimport.cpp
@@ -83,7 +83,7 @@ public:
QDeclarativeType** type_return, QUrl* url_return,
QUrl *base = 0, bool *typeRecursionDetected = 0);
bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
- QUrl* url_return, QUrl *base = 0, QString *errorString = 0);
+ QUrl* url_return, QUrl *base = 0, QList<QDeclarativeError> *errors = 0);
};
class QDeclarativeImportsPrivate {
@@ -93,15 +93,15 @@ public:
bool importExtension(const QString &absoluteFilePath, const QString &uri,
QDeclarativeImportDatabase *database, QDeclarativeDirComponents* components,
- QString *errorString);
+ QList<QDeclarativeError> *errors);
QString resolvedUri(const QString &dir_arg, QDeclarativeImportDatabase *database);
bool add(const QDeclarativeDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix,
int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType,
- QDeclarativeImportDatabase *database, QString *errorString);
+ QDeclarativeImportDatabase *database, QList<QDeclarativeError> *errors);
bool find(const QByteArray& type, int *vmajor, int *vminor,
- QDeclarativeType** type_return, QUrl* url_return, QString *errorString);
+ QDeclarativeType** type_return, QUrl* url_return, QList<QDeclarativeError> *errors);
QDeclarativeImportedNamespace *findNamespace(const QString& type);
@@ -163,7 +163,7 @@ QUrl QDeclarativeImports::baseUrl() const
static QDeclarativeTypeNameCache *
cacheForNamespace(QDeclarativeEngine *engine, const QDeclarativeImportedNamespace &set,
- QDeclarativeTypeNameCache *cache)
+ QDeclarativeTypeNameCache *cache, bool importWasQualified)
{
if (!cache)
cache = new QDeclarativeTypeNameCache(engine);
@@ -171,10 +171,27 @@ cacheForNamespace(QDeclarativeEngine *engine, const QDeclarativeImportedNamespac
QList<QDeclarativeType *> types = QDeclarativeMetaType::qmlTypes();
for (int ii = 0; ii < set.uris.count(); ++ii) {
- QByteArray base = set.uris.at(ii).toUtf8() + '/';
+ QByteArray uri = set.uris.at(ii).toUtf8();
int major = set.majversions.at(ii);
int minor = set.minversions.at(ii);
+ if (importWasQualified) {
+ QDeclarativeMetaType::ModuleApi moduleApi = QDeclarativeMetaType::moduleApi(uri, major, minor);
+ if (moduleApi.script || moduleApi.qobject) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QDeclarativeMetaType::ModuleApiInstance *a = ep->moduleApiInstances.value(moduleApi);
+ if (!a) {
+ a = new QDeclarativeMetaType::ModuleApiInstance;
+ a->scriptCallback = moduleApi.script;
+ a->qobjectCallback = moduleApi.qobject;
+ ep->moduleApiInstances.insert(moduleApi, a);
+ }
+ cache->setModuleApi(a);
+ }
+ }
+
+ QByteArray base = uri + '/';
+
foreach (QDeclarativeType *type, types) {
if (type->qmlTypeName().startsWith(base) &&
type->qmlTypeName().lastIndexOf('/') == (base.length() - 1) &&
@@ -200,15 +217,15 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
QDeclarativeTypeNameCache::Data *d = cache->data(iter.key());
if (d) {
if (!d->typeNamespace)
- cacheForNamespace(engine, *(*iter), d->typeNamespace);
+ cacheForNamespace(engine, *(*iter), d->typeNamespace, true);
} else {
- QDeclarativeTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0);
+ QDeclarativeTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0, true);
cache->add(iter.key(), nc);
nc->release();
}
}
- cacheForNamespace(engine, set, cache);
+ cacheForNamespace(engine, set, cache, false);
}
/*!
@@ -227,7 +244,7 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
*/
bool QDeclarativeImports::resolveType(const QByteArray& type,
QDeclarativeType** type_return, QUrl* url_return, int *vmaj, int *vmin,
- QDeclarativeImportedNamespace** ns_return, QString *errorString) const
+ QDeclarativeImportedNamespace** ns_return, QList<QDeclarativeError> *errors) const
{
QDeclarativeImportedNamespace* ns = d->findNamespace(QString::fromUtf8(type));
if (ns) {
@@ -236,7 +253,7 @@ bool QDeclarativeImports::resolveType(const QByteArray& type,
return true;
}
if (type_return || url_return) {
- if (d->find(type,vmaj,vmin,type_return,url_return, errorString)) {
+ if (d->find(type,vmaj,vmin,type_return,url_return, errors)) {
if (qmlImportTrace()) {
if (type_return && *type_return && url_return && !url_return->isEmpty())
qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
@@ -351,13 +368,16 @@ QDeclarativeImportsPrivate::~QDeclarativeImportsPrivate()
bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath, const QString &uri,
QDeclarativeImportDatabase *database,
- QDeclarativeDirComponents* components, QString *errorString)
+ QDeclarativeDirComponents* components, QList<QDeclarativeError> *errors)
{
QFile file(absoluteFilePath);
QString filecontent;
if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(uri).arg(absoluteFilePath);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(uri).arg(absoluteFilePath));
+ errors->prepend(error);
+ }
return false;
} else if (file.open(QFile::ReadOnly)) {
filecontent = QString::fromUtf8(file.readAll());
@@ -365,15 +385,29 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
qDebug().nospace() << "QDeclarativeImports(" << qPrintable(base.toString()) << "::importExtension: "
<< "loaded " << absoluteFilePath;
} else {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" definition \"%2\" not readable").arg(uri).arg(absoluteFilePath);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" definition \"%2\" not readable").arg(uri).arg(absoluteFilePath));
+ errors->prepend(error);
+ }
return false;
}
QDir dir = QFileInfo(file).dir();
+ QUrl url = QUrl::fromLocalFile(absoluteFilePath);
QDeclarativeDirParser qmldirParser;
qmldirParser.setSource(filecontent);
- qmldirParser.parse();
+ qmldirParser.setUrl(url);
+
+ // propagate any errors reported by the parser back up to the typeloader.
+ if (qmldirParser.parse()) {
+ if (errors) {
+ for (int i = 0; i < qmldirParser.errors().size(); ++i) {
+ errors->prepend(qmldirParser.errors().at(i));
+ }
+ }
+ return false;
+ }
if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) {
qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath);
@@ -390,14 +424,26 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
}
#endif
if (!resolvedFilePath.isEmpty()) {
- if (!database->importPlugin(resolvedFilePath, uri, errorString)) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(*errorString);
+ if (!database->importPlugin(resolvedFilePath, uri, errors)) {
+ if (errors) {
+ // XXX TODO: should we leave the import plugin error alone?
+ // Here, we pop it off the top and coalesce it into this error's message.
+ // The reason is that the lower level may add url and line/column numbering information.
+ QDeclarativeError poppedError = errors->takeFirst();
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(poppedError.description()));
+ error.setUrl(url);
+ errors->prepend(error);
+ }
return false;
}
} else {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name));
+ error.setUrl(url);
+ errors->prepend(error);
+ }
return false;
}
}
@@ -443,7 +489,7 @@ QString QDeclarativeImportsPrivate::resolvedUri(const QString &dir_arg, QDeclara
bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix, int vmaj, int vmin,
QDeclarativeScriptParser::Import::Type importType,
- QDeclarativeImportDatabase *database, QString *errorString)
+ QDeclarativeImportDatabase *database, QList<QDeclarativeError> *errors)
{
QDeclarativeDirComponents qmldircomponents = qmldircomponentsnetwork;
QString uri = uri_arg;
@@ -477,7 +523,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
- if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
return false;
break;
}
@@ -496,7 +542,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
- if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
return false;
break;
}
@@ -516,7 +562,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
- if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
return false;
break;
}
@@ -527,12 +573,14 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
versionFound = true;
if (!versionFound && qmldircomponents.isEmpty()) {
- if (errorString) {
+ if (errors) {
bool anyversion = QDeclarativeMetaType::isModule(uri.toUtf8(), -1, -1);
+ QDeclarativeError error; // we don't set the url or line or column as these will be set by the loader.
if (anyversion)
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin);
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
else
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg);
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg));
+ errors->prepend(error);
}
return false;
}
@@ -545,15 +593,19 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
QString dir = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
QFileInfo dirinfo(dir);
if (dir.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg);
+ if (errors) {
+ QDeclarativeError error; // we don't set the line or column as these will be set by the loader.
+ error.setDescription(QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg));
+ error.setUrl(importUrl);
+ errors->prepend(error);
+ }
return false; // local import dirs must exist
}
uri = resolvedUri(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri))), database);
if (uri.endsWith(QLatin1Char('/')))
uri.chop(1);
if (QFile::exists(localFileOrQrc)) {
- if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errorString))
+ if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errors))
return false;
}
} else {
@@ -562,11 +614,14 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
QFileInfo dirinfo(localFileOrQrc);
if (localFileOrQrc.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
- if (errorString) {
+ if (errors) {
+ QDeclarativeError error; // we don't set the line or column as these will be set by the loader.
if (localFileOrQrc.isEmpty())
- *errorString = QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri);
+ error.setDescription(QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri));
else
- *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri);
+ error.setDescription(QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri));
+ error.setUrl(importUrl);
+ errors->prepend(error);
}
return false;
}
@@ -598,7 +653,11 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
if (lowest_maj > vmaj || (lowest_maj == vmaj && lowest_min > vmin)
|| highest_maj < vmaj || (highest_maj == vmaj && highest_min < vmin))
{
- *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin);
+ if (errors) {
+ QDeclarativeError error; // we don't set the url or line or column information, as these will be set by the loader.
+ error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
+ errors->prepend(error);
+ }
return false;
}
}
@@ -613,7 +672,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
}
bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
- QUrl* url_return, QString *errorString)
+ QUrl* url_return, QList<QDeclarativeError> *errors)
{
QDeclarativeImportedNamespace *s = 0;
int slash = type.indexOf('/');
@@ -621,14 +680,20 @@ bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *
QString namespaceName = QString::fromUtf8(type.left(slash));
s = set.value(namespaceName);
if (!s) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("- %1 is not a namespace").arg(namespaceName);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("- %1 is not a namespace").arg(namespaceName));
+ errors->prepend(error);
+ }
return false;
}
int nslash = type.indexOf('/',slash+1);
if (nslash > 0) {
- if (errorString)
- *errorString = QDeclarativeImportDatabase::tr("- nested namespaces not allowed");
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(QDeclarativeImportDatabase::tr("- nested namespaces not allowed"));
+ errors->prepend(error);
+ }
return false;
}
} else {
@@ -636,7 +701,7 @@ bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *
}
QByteArray unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower)
if (s) {
- if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errorString))
+ if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errors))
return true;
if (s->urls.count() == 1 && !s->isLibrary[0] && url_return && s != &unqualifiedset) {
// qualified, and only 1 url
@@ -654,7 +719,7 @@ QDeclarativeImportedNamespace *QDeclarativeImportsPrivate::findNamespace(const Q
}
bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
- QUrl* url_return, QUrl *base, QString *errorString)
+ QUrl* url_return, QUrl *base, QList<QDeclarativeError> *errors)
{
bool typeRecursionDetected = false;
for (int i=0; i<urls.count(); ++i) {
@@ -663,7 +728,7 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
// check for type clashes
for (int j = i+1; j<urls.count(); ++j) {
if (find_helper(j, type, vmajor, vminor, 0, 0, base)) {
- if (errorString) {
+ if (errors) {
QString u1 = urls.at(i);
QString u2 = urls.at(j);
if (base) {
@@ -683,16 +748,16 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
}
}
- if (u1 != u2)
- *errorString
- = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 and in %2")
- .arg(u1).arg(u2);
- else
- *errorString
- = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
- .arg(u1)
- .arg(majversions.at(i)).arg(minversions.at(i))
- .arg(majversions.at(j)).arg(minversions.at(j));
+ QDeclarativeError error;
+ if (u1 != u2) {
+ error.setDescription(QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 and in %2").arg(u1).arg(u2));
+ } else {
+ error.setDescription(QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
+ .arg(u1)
+ .arg(majversions.at(i)).arg(minversions.at(i))
+ .arg(majversions.at(j)).arg(minversions.at(j)));
+ }
+ errors->prepend(error);
}
return false;
}
@@ -701,11 +766,13 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
return true;
}
}
- if (errorString) {
+ if (errors) {
+ QDeclarativeError error;
if (typeRecursionDetected)
- *errorString = QDeclarativeImportDatabase::tr("is instantiated recursively");
+ error.setDescription(QDeclarativeImportDatabase::tr("is instantiated recursively"));
else
- *errorString = QDeclarativeImportDatabase::tr("is not a type");
+ error.setDescription(QDeclarativeImportDatabase::tr("is not a type"));
+ errors->prepend(error);
}
return false;
}
@@ -790,7 +857,7 @@ bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb,
const QString& uri, const QString& prefix, int vmaj, int vmin,
QDeclarativeScriptParser::Import::Type importType,
const QDeclarativeDirComponents &qmldircomponentsnetwork,
- QString *errorString)
+ QList<QDeclarativeError> *errors)
{
if (qmlImportTrace())
qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::addImport: "
@@ -798,7 +865,7 @@ bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb,
<< (importType==QDeclarativeScriptParser::Import::Library? "Library" : "File")
<< " as " << prefix;
- return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errorString);
+ return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errors);
}
/*!
@@ -1013,7 +1080,7 @@ void QDeclarativeImportDatabase::setImportPathList(const QStringList &paths)
/*!
\internal
*/
-bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
+bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors)
{
if (qmlImportTrace())
qDebug().nospace() << "QDeclarativeImportDatabase::importPlugin: " << uri << " from " << filePath;
@@ -1033,15 +1100,21 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt
if (!engineInitialized || !typesRegistered) {
if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
- if (errorString)
- *errorString = tr("File name case mismatch for \"%2\"").arg(absoluteFilePath);
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(tr("File name case mismatch for \"%2\"").arg(absoluteFilePath));
+ errors->prepend(error);
+ }
return false;
}
QPluginLoader loader(absoluteFilePath);
if (!loader.load()) {
- if (errorString)
- *errorString = loader.errorString();
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(loader.errorString());
+ errors->prepend(error);
+ }
return false;
}
@@ -1063,8 +1136,11 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt
iface->initializeEngine(engine, moduleId);
}
} else {
- if (errorString)
- *errorString = loader.errorString();
+ if (errors) {
+ QDeclarativeError error;
+ error.setDescription(loader.errorString());
+ errors->prepend(error);
+ }
return false;
}
}
diff --git a/src/declarative/qml/qdeclarativeimport_p.h b/src/declarative/qml/qdeclarativeimport_p.h
index 1c910fd5bf..9d140bf106 100644
--- a/src/declarative/qml/qdeclarativeimport_p.h
+++ b/src/declarative/qml/qdeclarativeimport_p.h
@@ -84,7 +84,7 @@ public:
QDeclarativeType** type_return, QUrl* url_return,
int *version_major, int *version_minor,
QDeclarativeImportedNamespace** ns_return,
- QString *errorString = 0) const;
+ QList<QDeclarativeError> *errors = 0) const;
bool resolveType(QDeclarativeImportedNamespace*,
const QByteArray& type,
QDeclarativeType** type_return, QUrl* url_return,
@@ -94,7 +94,7 @@ public:
const QString& uri, const QString& prefix, int vmaj, int vmin,
QDeclarativeScriptParser::Import::Type importType,
const QDeclarativeDirComponents &qmldircomponentsnetwork,
- QString *errorString);
+ QList<QDeclarativeError> *errors);
void populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *) const;
@@ -110,7 +110,7 @@ public:
QDeclarativeImportDatabase(QDeclarativeEngine *);
~QDeclarativeImportDatabase();
- bool importPlugin(const QString &filePath, const QString &uri, QString *errorString);
+ bool importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors);
QStringList importPathList() const;
void setImportPathList(const QStringList &paths);
diff --git a/src/declarative/qml/qdeclarativeinfo.cpp b/src/declarative/qml/qdeclarativeinfo.cpp
index 7c8f73bc61..8449578c65 100644
--- a/src/declarative/qml/qdeclarativeinfo.cpp
+++ b/src/declarative/qml/qdeclarativeinfo.cpp
@@ -129,6 +129,18 @@ QDeclarativeInfo::~QDeclarativeInfo()
int marker = typeName.indexOf(QLatin1String("_QMLTYPE_"));
if (marker != -1)
typeName = typeName.left(marker);
+
+ marker = typeName.indexOf(QLatin1String("_QML_"));
+ if (marker != -1) {
+ typeName = typeName.left(marker) + "*";
+ type = QDeclarativeMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
+ if (type) {
+ typeName = QLatin1String(type->qmlTypeName());
+ int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash != -1)
+ typeName = typeName.mid(lastSlash+1);
+ }
+ }
}
d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": "));
diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp
index 0c99cefb04..556b7bc343 100644
--- a/src/declarative/qml/qdeclarativeinstruction.cpp
+++ b/src/declarative/qml/qdeclarativeinstruction.cpp
@@ -96,6 +96,9 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx)
case QDeclarativeInstruction::StoreString:
qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
break;
+ case QDeclarativeInstruction::StoreByteArray:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BYTEARRAY" << instr->storeByteArray.propertyIndex << "\t" << instr->storeByteArray.value << "\t\t" << datas.at(instr->storeByteArray.value);
+ break;
case QDeclarativeInstruction::StoreUrl:
qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value);
break;
diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h
index 20be889252..a5521b6425 100644
--- a/src/declarative/qml/qdeclarativeinstruction_p.h
+++ b/src/declarative/qml/qdeclarativeinstruction_p.h
@@ -88,6 +88,7 @@ public:
// StoreInteger - Store a int or uint in a core property
// StoreBool - Store a bool in a core property
// StoreString - Store a QString in a core property
+ // StoreByteArray - Store a QByteArray in a core property
// StoreUrl - Store a QUrl in a core property
// StoreColor - Store a QColor in a core property
// StoreDate - Store a QDate in a core property
@@ -101,6 +102,7 @@ public:
StoreInteger, /* storeInteger */
StoreBool, /* storeBool */
StoreString, /* storeString */
+ StoreByteArray, /* storeByteArray */
StoreUrl, /* storeUrl */
StoreColor, /* storeColor */
StoreDate, /* storeDate */
@@ -245,6 +247,10 @@ public:
int propertyIndex;
int value;
};
+ struct StoreByteArrayInstruction {
+ int propertyIndex;
+ int value;
+ };
struct StoreScriptStringInstruction {
int propertyIndex;
int value;
@@ -332,6 +338,7 @@ public:
StoreIntegerInstruction storeInteger;
StoreBoolInstruction storeBool;
StoreStringInstruction storeString;
+ StoreByteArrayInstruction storeByteArray;
StoreScriptStringInstruction storeScriptString;
StoreScriptInstruction storeScript;
StoreUrlInstruction storeUrl;
diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp
index bf1f699c72..ede02e9f30 100644
--- a/src/declarative/qml/qdeclarativemetatype.cpp
+++ b/src/declarative/qml/qdeclarativemetatype.cpp
@@ -88,6 +88,7 @@ QT_BEGIN_NAMESPACE
struct QDeclarativeMetaTypeData
{
+ QDeclarativeMetaTypeData();
~QDeclarativeMetaTypeData();
QList<QDeclarativeType *> types;
typedef QHash<int, QDeclarativeType *> Ids;
@@ -98,6 +99,14 @@ struct QDeclarativeMetaTypeData
MetaObjects metaObjectToType;
typedef QHash<int, QDeclarativeMetaType::StringConverter> StringConverters;
StringConverters stringConverters;
+ struct ModuleApiList {
+ ModuleApiList() : sorted(true) {}
+ QList<QDeclarativeMetaType::ModuleApi> moduleApis;
+ bool sorted;
+ };
+ typedef QHash<QByteArray, ModuleApiList> ModuleApis;
+ ModuleApis moduleApis;
+ int moduleApiCount;
struct ModuleInfo {
ModuleInfo(int major, int minor)
@@ -119,6 +128,11 @@ struct QDeclarativeMetaTypeData
Q_GLOBAL_STATIC(QDeclarativeMetaTypeData, metaTypeData)
Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
+QDeclarativeMetaTypeData::QDeclarativeMetaTypeData()
+: moduleApiCount(0)
+{
+}
+
QDeclarativeMetaTypeData::~QDeclarativeMetaTypeData()
{
for (int i = 0; i < types.count(); ++i)
@@ -664,6 +678,34 @@ int registerType(const QDeclarativePrivate::RegisterType &type)
return index;
}
+int registerModuleApi(const QDeclarativePrivate::RegisterModuleApi &api)
+{
+ QWriteLocker lock(metaTypeDataLock());
+
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ QByteArray uri(api.uri);
+ QDeclarativeMetaType::ModuleApi import;
+ import.major = api.versionMajor;
+ import.minor = api.versionMinor;
+ import.script = api.scriptApi;
+ import.qobject = api.qobjectApi;
+
+ int index = data->moduleApiCount++;
+
+ QDeclarativeMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
+ if (iter == data->moduleApis.end()) {
+ QDeclarativeMetaTypeData::ModuleApiList apis;
+ apis.moduleApis << import;
+ data->moduleApis.insert(uri, apis);
+ } else {
+ iter->moduleApis << import;
+ iter->sorted = false;
+ }
+
+ return index;
+}
+
+
/*
This method is "over generalized" to allow us to (potentially) register more types of things in
the future without adding exported symbols.
@@ -676,13 +718,16 @@ int QDeclarativePrivate::qmlregister(RegistrationType type, void *data)
return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
} else if (type == AutoParentRegistration) {
return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
+ } else if (type == ModuleApiRegistration) {
+ return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
}
return -1;
}
/*
- Have any types been registered for \a module with at least versionMajor.versionMinor, and types
- for \a module with at most versionMajor.versionMinor.
+ Returns true if any type or API has been registered for the given \a module with at least
+ versionMajor.versionMinor, or if types have been registered for \a module with at most
+ versionMajor.versionMinor.
So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10.
@@ -691,13 +736,27 @@ int QDeclarativePrivate::qmlregister(RegistrationType type, void *data)
bool QDeclarativeMetaType::isModule(const QByteArray &module, int versionMajor, int versionMinor)
{
QDeclarativeMetaTypeData *data = metaTypeData();
+
+ // first, check Types
QDeclarativeMetaTypeData::ModuleInfoHash::Iterator it = data->modules.find(module);
- return it != data->modules.end()
+ if (it != data->modules.end()
&& ((versionMajor<0 && versionMinor<0) ||
(((*it).vmajor_max > versionMajor ||
((*it).vmajor_max == versionMajor && (*it).vminor_max >= versionMinor))
&& ((*it).vmajor_min < versionMajor ||
- ((*it).vmajor_min == versionMajor && (*it).vminor_min <= versionMinor))));
+ ((*it).vmajor_min == versionMajor && (*it).vminor_min <= versionMinor))))) {
+ return true;
+ }
+
+ // then, check ModuleApis
+ foreach (const QDeclarativeMetaType::ModuleApi &mApi, data->moduleApis.value(module).moduleApis) {
+ if ((versionMajor<0 && versionMinor<0)
+ || (mApi.major == versionMajor && mApi.minor == versionMinor)) {
+ return true;
+ }
+ }
+
+ return false;
}
QList<QDeclarativePrivate::AutoParentFunction> QDeclarativeMetaType::parentFunctions()
@@ -707,6 +766,35 @@ QList<QDeclarativePrivate::AutoParentFunction> QDeclarativeMetaType::parentFunct
return data->parentFunctions;
}
+static bool operator<(const QDeclarativeMetaType::ModuleApi &lhs, const QDeclarativeMetaType::ModuleApi &rhs)
+{
+ return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
+}
+
+QDeclarativeMetaType::ModuleApi
+QDeclarativeMetaType::moduleApi(const QByteArray &uri, int versionMajor, int versionMinor)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ QDeclarativeMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
+ if (iter == data->moduleApis.end())
+ return ModuleApi();
+
+ if (iter->sorted == false) {
+ qSort(iter->moduleApis.begin(), iter->moduleApis.end());
+ iter->sorted = true;
+ }
+
+ for (int ii = iter->moduleApis.count() - 1; ii >= 0; --ii) {
+ const ModuleApi &import = iter->moduleApis.at(ii);
+ if (import.major == versionMajor && import.minor <= versionMinor)
+ return import;
+ }
+
+ return ModuleApi();
+}
+
QObject *QDeclarativeMetaType::toQObject(const QVariant &v, bool *ok)
{
if (!isQObject(v.userType())) {
diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h
index aab1c31ef5..291bc38222 100644
--- a/src/declarative/qml/qdeclarativemetatype_p.h
+++ b/src/declarative/qml/qdeclarativemetatype_p.h
@@ -59,6 +59,7 @@
#include <QtCore/qvariant.h>
#include <QtCore/qbitarray.h>
#include <private/qdeclarativeglobal_p.h>
+#include <QtScript/qscriptvalue.h>
QT_BEGIN_NAMESPACE
@@ -106,6 +107,25 @@ public:
static bool isModule(const QByteArray &module, int versionMajor, int versionMinor);
static QList<QDeclarativePrivate::AutoParentFunction> parentFunctions();
+
+ struct ModuleApiInstance {
+ ModuleApiInstance()
+ : scriptCallback(0), qobjectCallback(0), qobjectApi(0) {}
+
+ QScriptValue (*scriptCallback)(QDeclarativeEngine *, QScriptEngine *);
+ QObject *(*qobjectCallback)(QDeclarativeEngine *, QScriptEngine *);
+ QScriptValue scriptApi;
+ QObject *qobjectApi;
+ };
+ struct ModuleApi {
+ inline ModuleApi();
+ inline bool operator==(const ModuleApi &) const;
+ int major;
+ int minor;
+ QScriptValue (*script)(QDeclarativeEngine *, QScriptEngine *);
+ QObject *(*qobject)(QDeclarativeEngine *, QScriptEngine *);
+ };
+ static ModuleApi moduleApi(const QByteArray &, int, int);
};
class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeType
@@ -168,6 +188,25 @@ private:
QDeclarativeTypePrivate *d;
};
+QDeclarativeMetaType::ModuleApi::ModuleApi()
+// : major(0), minor(0), script(0), qobject(0)
+{
+ major = 0;
+ minor = 0;
+ script = 0;
+ qobject = 0;
+}
+
+bool QDeclarativeMetaType::ModuleApi::operator==(const ModuleApi &other) const
+{
+ return major == other.major && minor == other.minor && script == other.script && qobject == other.qobject;
+}
+
+inline uint qHash(const QDeclarativeMetaType::ModuleApi &import)
+{
+ return import.major ^ import.minor ^ quintptr(import.script) ^ quintptr(import.qobject);
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVEMETATYPE_P_H
diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
index 9eecc65e3c..edc1755a72 100644
--- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
+++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
@@ -403,6 +403,33 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj,
} else if (value.isFunction() && !value.isRegExp()) {
// this is handled by the binding creation above
} else {
+ //### expand optimization for other known types
+ if (lastData->propType == QMetaType::Int && value.isNumber()) {
+ int rawValue = qRound(value.toNumber());
+ int status = -1;
+ int flags = 0;
+ void *a[] = { (void *)&rawValue, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty,
+ lastData->coreIndex, a);
+ return;
+ } else if (lastData->propType == QMetaType::QReal && value.isNumber()) {
+ qreal rawValue = qreal(value.toNumber());
+ int status = -1;
+ int flags = 0;
+ void *a[] = { (void *)&rawValue, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty,
+ lastData->coreIndex, a);
+ return;
+ } else if (lastData->propType == QMetaType::QString && value.isString()) {
+ const QString &rawValue = value.toString();
+ int status = -1;
+ int flags = 0;
+ void *a[] = { (void *)&rawValue, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty,
+ lastData->coreIndex, a);
+ return;
+ }
+
QVariant v;
if (lastData->flags & QDeclarativePropertyCache::Data::IsQList)
v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >());
diff --git a/src/declarative/qml/qdeclarativeprivate.h b/src/declarative/qml/qdeclarativeprivate.h
index 7ac3369fc7..fea9eae109 100644
--- a/src/declarative/qml/qdeclarativeprivate.h
+++ b/src/declarative/qml/qdeclarativeprivate.h
@@ -74,6 +74,9 @@ public:
};
+class QScriptValue;
+class QScriptEngine;
+class QDeclarativeEngine;
class QDeclarativeCustomParser;
namespace QDeclarativePrivate
{
@@ -233,10 +236,22 @@ namespace QDeclarativePrivate
AutoParentFunction function;
};
+ struct RegisterModuleApi {
+ int version;
+
+ const char *uri;
+ int versionMajor;
+ int versionMinor;
+
+ QScriptValue (*scriptApi)(QDeclarativeEngine *, QScriptEngine *);
+ QObject *(*qobjectApi)(QDeclarativeEngine *, QScriptEngine *);
+ };
+
enum RegistrationType {
TypeRegistration = 0,
InterfaceRegistration = 1,
- AutoParentRegistration = 2
+ AutoParentRegistration = 2,
+ ModuleApiRegistration = 3,
};
int Q_DECLARATIVE_EXPORT qmlregister(RegistrationType, void *);
diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp
index 6a39a65532..9cbb4fa8cc 100644
--- a/src/declarative/qml/qdeclarativepropertycache.cpp
+++ b/src/declarative/qml/qdeclarativepropertycache.cpp
@@ -61,6 +61,8 @@ QDeclarativePropertyCache::Data::Flags QDeclarativePropertyCache::Data::flagsFor
flags |= Data::IsWritable;
if (p.isResettable())
flags |= Data::IsResettable;
+ if (p.isFinal())
+ flags |= Data::IsFinal;
if (propType == qMetaTypeId<QDeclarativeBinding *>()) {
flags |= Data::IsQmlBinding;
diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h
index eeeff1aea1..65a8725b8f 100644
--- a/src/declarative/qml/qdeclarativepropertycache_p.h
+++ b/src/declarative/qml/qdeclarativepropertycache_p.h
@@ -84,20 +84,21 @@ public:
IsWritable = 0x00000002,
IsResettable = 0x00000004,
IsAlias = 0x00000008,
+ IsFinal = 0x00000010,
// These are mutualy exclusive
- IsFunction = 0x00000010,
- IsQObjectDerived = 0x00000020,
- IsEnumType = 0x00000040,
- IsQList = 0x00000080,
- IsQmlBinding = 0x00000100,
- IsQScriptValue = 0x00000200,
+ IsFunction = 0x00000020,
+ IsQObjectDerived = 0x00000040,
+ IsEnumType = 0x00000080,
+ IsQList = 0x00000100,
+ IsQmlBinding = 0x00000200,
+ IsQScriptValue = 0x00000400,
// Apply only to IsFunctions
- IsVMEFunction = 0x00000400,
- HasArguments = 0x00000800,
- IsSignal = 0x00001000,
- IsVMESignal = 0x00002000
+ IsVMEFunction = 0x00000800,
+ HasArguments = 0x00001000,
+ IsSignal = 0x00002000,
+ IsVMESignal = 0x00004000
};
Q_DECLARE_FLAGS(Flags, Flag)
diff --git a/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp b/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp
new file mode 100644
index 0000000000..121d0a1a35
--- /dev/null
+++ b/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativescarceresourcescriptclass_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativedata_p.h"
+#include "private/qdeclarativetypenamescriptclass_p.h"
+#include "private/qdeclarativelistscriptclass_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativeguard_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtScript/qscriptcontextinfo.h>
+
+Q_DECLARE_METATYPE(QScriptValue);
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeScarceResourceScriptClass::QDeclarativeScarceResourceScriptClass(QDeclarativeEngine *bindEngine)
+ : QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ // Properties of this type can be explicitly preserved by clients,
+ // which prevents the scarce resource from being automatically
+ // released after the binding has been evaluated.
+ m_preserve = scriptEngine->newFunction(preserve);
+ m_preserveId = createPersistentIdentifier(QLatin1String("preserve"));
+
+ // Similarly, they can be explicitly destroyed by clients,
+ // which releases the scarce resource.
+ m_destroy = scriptEngine->newFunction(destroy);
+ m_destroyId = createPersistentIdentifier(QLatin1String("destroy"));
+}
+
+QDeclarativeScarceResourceScriptClass::~QDeclarativeScarceResourceScriptClass()
+{
+}
+
+/*
+ Returns a JavaScript object whose instance data is a new scarce resource data.
+ The scarce resource is added to the doubly-linked-list of scarce resources in the engine
+ so that the scarce resource can be released after evaluation completes.
+ */
+QScriptValue QDeclarativeScarceResourceScriptClass::newScarceResource(const QVariant &v)
+{
+ // create the scarce resource
+ ScarceResourceData *srd = new ScarceResourceData(v);
+
+ // insert into the linked list
+ QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
+ srd->insertInto(&enginePrivate->scarceResources);
+ Q_ASSERT(enginePrivate->scarceResourcesRefCount > 0);
+
+ // return the javascript object with the scarce resource instance data
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ return QScriptDeclarativeClass::newObject(scriptEngine, this, srd); // JSC takes ownership of srd.
+}
+
+QVariant QDeclarativeScarceResourceScriptClass::toVariant(Object *object, bool *ok)
+{
+ ScarceResourceData *obj = static_cast<ScarceResourceData*>(object);
+ if (ok) *ok = true;
+ return obj->resource;
+}
+
+QVariant QDeclarativeScarceResourceScriptClass::toVariant(const QScriptValue &value)
+{
+ Q_ASSERT(scriptClass(value) == this);
+
+ return toVariant(object(value), 0);
+}
+
+// The destroy() and preserve() function properties are readable.
+QScriptClass::QueryFlags
+QDeclarativeScarceResourceScriptClass::queryProperty(Object *object, const Identifier &name,
+ QScriptClass::QueryFlags flags)
+{
+ Q_UNUSED(object)
+ Q_UNUSED(flags)
+
+ if (name == m_destroyId.identifier || name == m_preserveId.identifier)
+ return (QScriptClass::HandlesReadAccess);
+ return 0;
+}
+
+// Return the (function) values which may be evaluated by clients.
+QDeclarativeScarceResourceScriptClass::Value
+QDeclarativeScarceResourceScriptClass::property(Object *object, const Identifier &name)
+{
+ Q_UNUSED(object)
+
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ // functions
+ if (name == m_preserveId.identifier)
+ return Value(scriptEngine, m_preserve);
+ else if (name == m_destroyId.identifier)
+ return Value(scriptEngine, m_destroy);
+
+ return Value();
+}
+
+/*
+ The user explicitly wants to preserve the resource.
+ We remove the scarce resource from the engine's linked list
+ of resources to release after evaluation completes.
+ */
+QScriptValue QDeclarativeScarceResourceScriptClass::preserve(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+ QScriptValue that = context->thisObject();
+
+ if (scriptClass(that) != p->scarceResourceClass)
+ return engine->undefinedValue();
+
+ // The client wishes to preserve the resource in this SRD.
+ ScarceResourceData *data = static_cast<ScarceResourceData *>(p->scarceResourceClass->object(that));
+ if (!data)
+ return engine->undefinedValue();
+
+ // remove node from list, without releasing the resource.
+ data->removeNode();
+
+ return engine->undefinedValue();
+}
+
+/*
+ The user explicitly wants to release the resource.
+ We set the internal scarce resource variant to the invalid variant.
+ */
+QScriptValue QDeclarativeScarceResourceScriptClass::destroy(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+ QScriptValue that = context->thisObject();
+
+ if (scriptClass(that) != p->scarceResourceClass)
+ return engine->undefinedValue();
+
+ // the client wishes to release the resource in this SRD.
+ ScarceResourceData *data = static_cast<ScarceResourceData *>(p->scarceResourceClass->object(that));
+ if (!data)
+ return engine->undefinedValue();
+
+ // release the resource and remove the node from the list.
+ data->releaseResource();
+
+ return engine->undefinedValue();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h b/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h
new file mode 100644
index 0000000000..2a1390a230
--- /dev/null
+++ b/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
+#define QDECLARATIVESCARCERESOURCESCRIPTCLASS_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/qdeclarativepropertycache_p.h"
+#include "private/qdeclarativetypenamecache_p.h"
+
+#include <private/qscriptdeclarativeclass_p.h>
+#include <QtScript/qscriptengine.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+
+/*
+ Scarce resources (like pixmaps and textures) are managed manually
+ in that the variant will be set to the invalid variant once the
+ JavaScript engine has finished using the JavaScript object whose
+ instance data is the ScarceResourceData (but before the garbage
+ collector frees the JavaScript object itself).
+
+ The engine stores a doubly-linked-list of scarce resources which
+ will to be cleaned up after a binding is successfully evaluated
+ (unless the user explicitly preserves the scarce resource).
+
+ A ScarceResourceData pointer should not be deleted manually, as
+ all instances of a ScarceResourceData should be owned by the
+ JavaScript engine.
+ */
+struct ScarceResourceData : public QScriptDeclarativeClass::Object {
+ ScarceResourceData(const QVariant &v) : resource(v), prev(0), next(0)
+ {
+ }
+
+ virtual ~ScarceResourceData()
+ {
+ releaseResource();
+ }
+
+ // Insert this resource into the given list of resources.
+ void insertInto(ScarceResourceData **list)
+ {
+ // This node becomes the head of the list.
+ next = *list; // so our next = old list head
+ *list = this; // list now points to us (we're the head)
+ prev = list; // as we're the head, our prev ptr becomes the list ptr.
+
+ // and the next node's prev pointer must contain a ptr to our next ptr,
+ // since per definition, prev always contains a pointer to the previous node's "next" ptr,
+ // and the "this" node is the "this->next" node's "prev" node.
+ if (next) next->prev = &next;
+ }
+
+ // Remove this resource from the list of resources, without releasing the resource.
+ void removeNode()
+ {
+ // whatever previously pointed to this node (ie, as that node's "next" node)
+ // should now point to our next node (since we no longer exist in the list).
+ // and the next node's prev ptr should point to our prev node.
+ if (prev) *prev = next;
+ if (next) next->prev = prev;
+ prev = 0;
+ next = 0;
+ }
+
+ // Release this resource, and remove from the list.
+ void releaseResource()
+ {
+ resource = QVariant();
+ removeNode();
+ }
+
+ QVariant resource;
+
+ // prev always contains a pointer to the previous node's "next" ptr.
+ // :. for the head node, [*prev] will be engine->scarceResources
+ // :. for every other node, [*prev] will be the previous node's "next" ptr.
+ ScarceResourceData **prev;
+ ScarceResourceData *next;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeScarceResourceScriptClass : public QScriptDeclarativeClass
+{
+public:
+ QDeclarativeScarceResourceScriptClass(QDeclarativeEngine *);
+ ~QDeclarativeScarceResourceScriptClass();
+
+ // Creates a new JavaScript object whose instance data is the scarce resource v
+ QScriptValue newScarceResource(const QVariant &v);
+
+ // inherited from QScriptDeclarativeClass
+ virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
+ QScriptClass::QueryFlags flags);
+ virtual Value property(Object *, const Identifier &);
+ virtual QVariant toVariant(Object *, bool *ok = 0);
+ QVariant toVariant(const QScriptValue &value);
+
+private:
+ PersistentIdentifier m_preserveId;
+ PersistentIdentifier m_destroyId;
+ QScriptValue m_preserve;
+ QScriptValue m_destroy;
+
+ static QScriptValue preserve(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine);
+
+ QDeclarativeEngine *engine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp
index e04cfc52af..352e341437 100644
--- a/src/declarative/qml/qdeclarativescriptparser.cpp
+++ b/src/declarative/qml/qdeclarativescriptparser.cpp
@@ -59,6 +59,22 @@ QT_BEGIN_NAMESPACE
using namespace QDeclarativeJS;
using namespace QDeclarativeParser;
+void QDeclarativeScriptParser::Import::extractVersion(int *maj, int *min) const
+{
+ *maj = -1; *min = -1;
+
+ if (!version.isEmpty()) {
+ int dot = version.indexOf(QLatin1Char('.'));
+ if (dot < 0) {
+ *maj = version.toInt();
+ *min = 0;
+ } else {
+ *maj = version.left(dot).toInt();
+ *min = version.mid(dot+1).toInt();
+ }
+ }
+}
+
namespace {
class ProcessAST: protected AST::Visitor
@@ -896,6 +912,19 @@ static void replaceWithSpace(QString &str, int idx, int n)
*data++ = space;
}
+static QDeclarativeParser::LocationSpan
+locationFromLexer(const QDeclarativeJS::Lexer &lex, int startLine, int startColumn, int startOffset)
+{
+ QDeclarativeParser::LocationSpan l;
+
+ l.start.line = startLine; l.start.column = startColumn;
+ l.end.line = lex.endLineNo(); l.end.column = lex.endColumnNo();
+ l.range.offset = startOffset;
+ l.range.length = lex.tokenOffset() + lex.tokenLength() - startOffset;
+
+ return l;
+}
+
/*
Searches for ".pragma <value>" declarations within \a script. Currently supported pragmas
are:
@@ -1024,7 +1053,8 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
return rv;
int startOffset = l.tokenOffset();
- int startLine = l.currentLineNo();
+ int startLine = l.startLineNo();
+ int startColumn = l.startColumnNo();
token = l.lex();
@@ -1062,8 +1092,11 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
if (!importId.at(0).isUpper())
return rv;
+ QDeclarativeParser::LocationSpan location =
+ locationFromLexer(l, startLine, startColumn, startOffset);
+
token = l.lex();
- if (l.currentLineNo() == startLine)
+ if (l.startLineNo() == startLine)
return rv;
replaceWithSpace(script, startOffset, endOffset - startOffset);
@@ -1072,9 +1105,9 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
import.type = Import::Script;
import.uri = file;
import.qualifier = importId;
+ import.location = location;
rv.imports << import;
-
} else {
// URI
QString uri;
@@ -1117,8 +1150,11 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
if (!importId.at(0).isUpper())
return rv;
+ QDeclarativeParser::LocationSpan location =
+ locationFromLexer(l, startLine, startColumn, startOffset);
+
token = l.lex();
- if (l.currentLineNo() == startLine)
+ if (l.startLineNo() == startLine)
return rv;
replaceWithSpace(script, startOffset, endOffset - startOffset);
@@ -1128,6 +1164,7 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
import.uri = uri;
import.version = version;
import.qualifier = importId;
+ import.location = location;
rv.imports << import;
}
@@ -1143,7 +1180,7 @@ QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMe
QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
int endOffset = l.tokenLength() + l.tokenOffset();
- if (pragmaValue == QLatin1String("library")) {
+ if (pragmaValue == library) {
pragmas |= QDeclarativeParser::Object::ScriptBlock::Shared;
replaceWithSpace(script, startOffset, endOffset - startOffset);
} else {
diff --git a/src/declarative/qml/qdeclarativescriptparser_p.h b/src/declarative/qml/qdeclarativescriptparser_p.h
index e5e0d7075d..fd89f757cc 100644
--- a/src/declarative/qml/qdeclarativescriptparser_p.h
+++ b/src/declarative/qml/qdeclarativescriptparser_p.h
@@ -82,6 +82,8 @@ public:
QString qualifier;
QString version;
+ void extractVersion(int *maj, int *min) const;
+
QDeclarativeParser::LocationSpan location;
};
diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp
index 26f3996871..1c1eeee2cf 100644
--- a/src/declarative/qml/qdeclarativetypeloader.cpp
+++ b/src/declarative/qml/qdeclarativetypeloader.cpp
@@ -607,7 +607,7 @@ void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArra
if (!blob->isError() && !blob->isWaiting())
blob->allDependenciesDone();
- if (blob->status() != QDeclarativeDataBlob::Error)
+ if (blob->status() != QDeclarativeDataBlob::Error)
blob->m_status = QDeclarativeDataBlob::WaitingForDependencies;
blob->m_inCallback = false;
@@ -674,24 +674,23 @@ QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const
}
/*!
-Return a QDeclarativeScriptData for \a url. The QDeclarativeScriptData may be cached.
+Return a QDeclarativeScriptBlob for \a url. The QDeclarativeScriptData may be cached.
*/
-QDeclarativeScriptData *QDeclarativeTypeLoader::getScript(const QUrl &url)
+QDeclarativeScriptBlob *QDeclarativeTypeLoader::getScript(const QUrl &url)
{
Q_ASSERT(!url.isRelative() &&
(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
!QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
- QDeclarativeScriptData *scriptData = m_scriptCache.value(url);
+ QDeclarativeScriptBlob *scriptBlob = m_scriptCache.value(url);
- if (!scriptData) {
- scriptData = new QDeclarativeScriptData(url);
- m_scriptCache.insert(url, scriptData);
- QDeclarativeDataLoader::load(scriptData);
+ if (!scriptBlob) {
+ scriptBlob = new QDeclarativeScriptBlob(url, this);
+ m_scriptCache.insert(url, scriptBlob);
+ QDeclarativeDataLoader::load(scriptBlob);
}
- scriptData->addref();
- return scriptData;
+ return scriptBlob;
}
/*!
@@ -868,13 +867,14 @@ void QDeclarativeTypeData::dataReceived(const QByteArray &data)
}
} else if (import.type == QDeclarativeScriptParser::Import::Script) {
QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
- QDeclarativeScriptData *data = typeLoader()->getScript(scriptUrl);
- addDependency(data);
+ QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob);
ScriptReference ref;
ref.location = import.location.start;
ref.qualifier = import.qualifier;
- ref.script = data;
+ ref.script = blob;
+ blob->addref();
m_scripts << ref;
}
@@ -933,14 +933,31 @@ void QDeclarativeTypeData::resolveTypes()
// For local urls, add an implicit import "." as first (most overridden) lookup.
// This will also trigger the loading of the qmldir and the import of any native
// types from available plugins.
+ QList<QDeclarativeError> errors;
if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) {
m_imports.addImport(importDatabase, QLatin1String("."),
QString(), -1, -1, QDeclarativeScriptParser::Import::File,
- qmldir->dirComponents(), 0);
+ qmldir->dirComponents(), &errors);
} else {
m_imports.addImport(importDatabase, QLatin1String("."),
QString(), -1, -1, QDeclarativeScriptParser::Import::File,
- QDeclarativeDirComponents(), 0);
+ QDeclarativeDirComponents(), &errors);
+ }
+
+ // remove any errors which are due to the implicit import which aren't real errors.
+ // for example, if the implicitly included qmldir file doesn't exist, that is not an error.
+ QList<QDeclarativeError> realErrors;
+ for (int i = 0; i < errors.size(); ++i) {
+ if (errors.at(i).description() != QDeclarativeImportDatabase::tr("import \".\" has no qmldir and no namespace")
+ && errors.at(i).description() != QDeclarativeImportDatabase::tr("\".\": no such directory")) {
+ realErrors.prepend(errors.at(i)); // this is a real error.
+ }
+ }
+
+ // report any real errors which occurred during plugin loading or qmldir parsing.
+ if (!realErrors.isEmpty()) {
+ setError(realErrors);
+ return;
}
foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
@@ -950,34 +967,31 @@ void QDeclarativeTypeData::resolveTypes()
if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
QUrl qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
- if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl))
+ if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl))
qmldircomponentsnetwork = qmldir->dirComponents();
}
int vmaj = -1;
int vmin = -1;
+ import.extractVersion(&vmaj, &vmin);
- if (!import.version.isEmpty()) {
- int dot = import.version.indexOf(QLatin1Char('.'));
- if (dot < 0) {
- vmaj = import.version.toInt();
- vmin = 0;
- } else {
- vmaj = import.version.left(dot).toInt();
- vmin = import.version.mid(dot+1).toInt();
- }
- }
-
- QString errorString;
+ QList<QDeclarativeError> errors;
if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
- vmaj, vmin, import.type, qmldircomponentsnetwork, &errorString)) {
+ vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) {
QDeclarativeError error;
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database"));
+ }
error.setUrl(m_imports.baseUrl());
- error.setDescription(errorString);
error.setLine(import.location.start.line);
error.setColumn(import.location.start.column);
+ errors.prepend(error); // put it back on the list after filling out information.
- setError(error);
+ setError(errors);
return;
}
}
@@ -991,29 +1005,38 @@ void QDeclarativeTypeData::resolveTypes()
int majorVersion;
int minorVersion;
QDeclarativeImportedNamespace *typeNamespace = 0;
- QString errorString;
+ QList<QDeclarativeError> errors;
if (!m_imports.resolveType(typeName, &ref.type, &url, &majorVersion, &minorVersion,
- &typeNamespace, &errorString) || typeNamespace) {
+ &typeNamespace, &errors) || typeNamespace) {
// Known to not be a type:
// - known to be a namespace (Namespace {})
// - type with unknown namespace (UnknownNamespace.SomeType {})
QDeclarativeError error;
- error.setUrl(m_imports.baseUrl());
QString userTypeName = parserRef->name;
userTypeName.replace(QLatin1Char('/'),QLatin1Char('.'));
- if (typeNamespace)
+ if (typeNamespace) {
error.setDescription(QDeclarativeTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName));
- else
- error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(errorString));
+ } else {
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QDeclarativeTypeLoader::tr("Unreported error adding script import to import database"));
+ }
+ error.setUrl(m_imports.baseUrl());
+ error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(error.description()));
+ }
if (!parserRef->refObjects.isEmpty()) {
QDeclarativeParser::Object *obj = parserRef->refObjects.first();
error.setLine(obj->location.start.line);
error.setColumn(obj->location.start.column);
}
-
- setError(error);
+
+ errors.prepend(error);
+ setError(errors);
return;
}
@@ -1046,25 +1069,156 @@ QDeclarativeQmldirData *QDeclarativeTypeData::qmldirForUrl(const QUrl &url)
return 0;
}
-QDeclarativeScriptData::QDeclarativeScriptData(const QUrl &url)
-: QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None)
+QDeclarativeScriptData::QDeclarativeScriptData(QDeclarativeEngine *engine)
+: QDeclarativeCleanup(engine), importCache(0), pragmas(QDeclarativeParser::Object::ScriptBlock::None),
+ m_loaded(false)
+{
+}
+
+QDeclarativeScriptData::~QDeclarativeScriptData()
{
+ clear();
}
-QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptData::pragmas() const
+void QDeclarativeScriptData::clear()
+{
+ if (importCache) {
+ importCache->release();
+ importCache = 0;
+ }
+
+ for (int ii = 0; ii < scripts.count(); ++ii)
+ scripts.at(ii)->release();
+ scripts.clear();
+}
+
+QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader)
+: QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None),
+ m_scriptData(0), m_typeLoader(loader)
+{
+}
+
+QDeclarativeScriptBlob::~QDeclarativeScriptBlob()
+{
+ if (m_scriptData) {
+ m_scriptData->release();
+ m_scriptData = 0;
+ }
+}
+
+QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptBlob::pragmas() const
{
return m_pragmas;
}
-QString QDeclarativeScriptData::scriptSource() const
+QString QDeclarativeScriptBlob::scriptSource() const
{
return m_source;
}
-void QDeclarativeScriptData::dataReceived(const QByteArray &data)
+QDeclarativeTypeLoader *QDeclarativeScriptBlob::typeLoader() const
+{
+ return m_typeLoader;
+}
+
+const QDeclarativeImports &QDeclarativeScriptBlob::imports() const
+{
+ return m_imports;
+}
+
+QDeclarativeScriptData *QDeclarativeScriptBlob::scriptData() const
+{
+ return m_scriptData;
+}
+
+void QDeclarativeScriptBlob::dataReceived(const QByteArray &data)
{
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine());
+ QDeclarativeImportDatabase *importDatabase = &ep->importDatabase;
+
m_source = QString::fromUtf8(data);
- m_pragmas = QDeclarativeScriptParser::extractPragmas(m_source);
+
+ QDeclarativeScriptParser::JavaScriptMetaData metadata =
+ QDeclarativeScriptParser::extractMetaData(m_source);
+
+ m_imports.setBaseUrl(finalUrl());
+
+ m_pragmas = metadata.pragmas;
+
+ foreach (const QDeclarativeScriptParser::Import &import, metadata.imports) {
+ Q_ASSERT(import.type != QDeclarativeScriptParser::Import::File);
+
+ if (import.type == QDeclarativeScriptParser::Import::Script) {
+ QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
+ QDeclarativeScriptBlob *blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob);
+
+ ScriptReference ref;
+ ref.location = import.location.start;
+ ref.qualifier = import.qualifier;
+ ref.script = blob;
+ blob->addref();
+ m_scripts << ref;
+ } else {
+ Q_ASSERT(import.type == QDeclarativeScriptParser::Import::Library);
+ int vmaj = -1;
+ int vmin = -1;
+ import.extractVersion(&vmaj, &vmin);
+
+ QList<QDeclarativeError> errors;
+ if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
+ import.type, QDeclarativeDirComponents(), &errors)) {
+ QDeclarativeError error = errors.takeFirst();
+ // description should be set by addImport().
+ error.setUrl(m_imports.baseUrl());
+ error.setLine(import.location.start.line);
+ error.setColumn(import.location.start.column);
+ errors.prepend(error);
+
+ setError(errors);
+ return;
+ }
+ }
+ }
+}
+
+void QDeclarativeScriptBlob::done()
+{
+ // Check all script dependencies for errors
+ for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+ Q_ASSERT(script.script->isCompleteOrError());
+ if (script.script->isError()) {
+ QList<QDeclarativeError> errors = script.script->errors();
+ QDeclarativeError error;
+ error.setUrl(finalUrl());
+ error.setLine(script.location.line);
+ error.setColumn(script.location.column);
+ error.setDescription(typeLoader()->tr("Script %1 unavailable").arg(script.script->url().toString()));
+ errors.prepend(error);
+ setError(errors);
+ }
+ }
+
+ if (isError())
+ return;
+
+ QDeclarativeEngine *engine = typeLoader()->engine();
+ m_scriptData = new QDeclarativeScriptData(engine);
+ m_scriptData->url = finalUrl();
+ m_scriptData->importCache = new QDeclarativeTypeNameCache(engine);
+
+ for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+
+ m_scriptData->scripts.append(script.script);
+ m_scriptData->importCache->add(script.qualifier, ii);
+ }
+
+ m_imports.populateCache(m_scriptData->importCache, engine);
+
+ m_scriptData->pragmas = m_pragmas;
+ m_scriptData->m_program = QScriptProgram(m_source, finalUrl().toString());
}
QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h
index 7f487a0e24..1c0798d67b 100644
--- a/src/declarative/qml/qdeclarativetypeloader_p.h
+++ b/src/declarative/qml/qdeclarativetypeloader_p.h
@@ -55,8 +55,11 @@
#include <QtCore/qobject.h>
#include <QtNetwork/qnetworkreply.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptprogram.h>
#include <QtDeclarative/qdeclarativeerror.h>
#include <QtDeclarative/qdeclarativeengine.h>
+#include <private/qdeclarativecleanup_p.h>
#include <private/qdeclarativescriptparser_p.h>
#include <private/qdeclarativedirparser_p.h>
#include <private/qdeclarativeimport_p.h>
@@ -64,6 +67,7 @@
QT_BEGIN_NAMESPACE
class QDeclarativeScriptData;
+class QDeclarativeScriptBlob;
class QDeclarativeQmldirData;
class QDeclarativeTypeLoader;
class QDeclarativeCompiledData;
@@ -140,7 +144,7 @@ private:
QUrl m_finalUrl;
// List of QDeclarativeDataBlob's that are waiting for me to complete.
- QList<QDeclarativeDataBlob *> m_waitingOnMe;
+ QList<QDeclarativeDataBlob *> m_waitingOnMe;
// List of QDeclarativeDataBlob's that I am waiting for to complete.
QList<QDeclarativeDataBlob *> m_waitingFor;
@@ -178,7 +182,6 @@ private:
NetworkReplies m_networkReplies;
};
-
class Q_AUTOTEST_EXPORT QDeclarativeTypeLoader : public QDeclarativeDataLoader
{
Q_OBJECT
@@ -196,11 +199,11 @@ public:
QDeclarativeTypeData *get(const QByteArray &, const QUrl &url, Options = None);
void clearCache();
- QDeclarativeScriptData *getScript(const QUrl &);
+ QDeclarativeScriptBlob *getScript(const QUrl &);
QDeclarativeQmldirData *getQmldir(const QUrl &);
private:
typedef QHash<QUrl, QDeclarativeTypeData *> TypeCache;
- typedef QHash<QUrl, QDeclarativeScriptData *> ScriptCache;
+ typedef QHash<QUrl, QDeclarativeScriptBlob *> ScriptCache;
typedef QHash<QUrl, QDeclarativeQmldirData *> QmldirCache;
TypeCache m_typeCache;
@@ -230,7 +233,7 @@ public:
QDeclarativeParser::Location location;
QString qualifier;
- QDeclarativeScriptData *script;
+ QDeclarativeScriptBlob *script;
};
QDeclarativeTypeData(const QUrl &, QDeclarativeTypeLoader::Options, QDeclarativeTypeLoader *);
@@ -285,20 +288,65 @@ private:
QDeclarativeTypeLoader *m_typeLoader;
};
-class Q_AUTOTEST_EXPORT QDeclarativeScriptData : public QDeclarativeDataBlob
+class Q_AUTOTEST_EXPORT QDeclarativeScriptData : public QDeclarativeRefCount, public QDeclarativeCleanup
{
public:
- QDeclarativeScriptData(const QUrl &);
+ QDeclarativeScriptData(QDeclarativeEngine *);
+ ~QDeclarativeScriptData();
+
+ QUrl url;
+ QDeclarativeTypeNameCache *importCache;
+ QList<QDeclarativeScriptBlob *> scripts;
+ QDeclarativeParser::Object::ScriptBlock::Pragmas pragmas;
+
+protected:
+ virtual void clear(); // From QDeclarativeCleanup
+
+private:
+ friend class QDeclarativeVME;
+ friend class QDeclarativeScriptBlob;
+
+ bool m_loaded;
+ QScriptProgram m_program;
+ QScriptValue m_value;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeScriptBlob : public QDeclarativeDataBlob
+{
+public:
+ QDeclarativeScriptBlob(const QUrl &, QDeclarativeTypeLoader *);
+ ~QDeclarativeScriptBlob();
+
+ struct ScriptReference
+ {
+ ScriptReference() : script(0) {}
+
+ QDeclarativeParser::Location location;
+ QString qualifier;
+ QDeclarativeScriptBlob *script;
+ };
QDeclarativeParser::Object::ScriptBlock::Pragmas pragmas() const;
QString scriptSource() const;
+ QDeclarativeTypeLoader *typeLoader() const;
+ const QDeclarativeImports &imports() const;
+
+ QDeclarativeScriptData *scriptData() const;
+
protected:
virtual void dataReceived(const QByteArray &);
+ virtual void done();
private:
QDeclarativeParser::Object::ScriptBlock::Pragmas m_pragmas;
QString m_source;
+
+ QDeclarativeImports m_imports;
+ QList<ScriptReference> m_scripts;
+ QDeclarativeScriptData *m_scriptData;
+
+ QDeclarativeTypeLoader *m_typeLoader;
};
class Q_AUTOTEST_EXPORT QDeclarativeQmldirData : public QDeclarativeDataBlob
diff --git a/src/declarative/qml/qdeclarativetypenamecache.cpp b/src/declarative/qml/qdeclarativetypenamecache.cpp
index 48c72a7fef..b9577c17fa 100644
--- a/src/declarative/qml/qdeclarativetypenamecache.cpp
+++ b/src/declarative/qml/qdeclarativetypenamecache.cpp
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
QDeclarativeTypeNameCache::QDeclarativeTypeNameCache(QDeclarativeEngine *e)
-: QDeclarativeCleanup(e), engine(e)
+: QDeclarativeCleanup(e), engine(e), m_moduleApi(0)
{
}
@@ -60,6 +60,7 @@ void QDeclarativeTypeNameCache::clear()
qDeleteAll(stringCache);
stringCache.clear();
identifierCache.clear();
+ m_moduleApi = 0;
engine = 0;
}
@@ -114,5 +115,10 @@ QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QString &
return stringCache.value(id);
}
+void QDeclarativeTypeNameCache::setModuleApi(QDeclarativeMetaType::ModuleApiInstance *api)
+{
+ m_moduleApi = api;
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativetypenamecache_p.h b/src/declarative/qml/qdeclarativetypenamecache_p.h
index f2562da777..bcca41f4d5 100644
--- a/src/declarative/qml/qdeclarativetypenamecache_p.h
+++ b/src/declarative/qml/qdeclarativetypenamecache_p.h
@@ -55,6 +55,7 @@
#include "private/qdeclarativerefcount_p.h"
#include "private/qdeclarativecleanup_p.h"
+#include "private/qdeclarativemetatype_p.h"
#include <private/qscriptdeclarativeclass_p.h>
@@ -82,6 +83,10 @@ public:
Data *data(const QString &) const;
inline Data *data(const QScriptDeclarativeClass::Identifier &id) const;
+ inline bool isEmpty() const;
+
+ inline QDeclarativeMetaType::ModuleApiInstance *moduleApi() const;
+ void setModuleApi(QDeclarativeMetaType::ModuleApiInstance *);
protected:
virtual void clear();
@@ -96,6 +101,7 @@ private:
StringCache stringCache;
IdentifierCache identifierCache;
QDeclarativeEngine *engine;
+ QDeclarativeMetaType::ModuleApiInstance *m_moduleApi;
};
QDeclarativeTypeNameCache::Data::Data()
@@ -113,6 +119,16 @@ QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QScriptDe
return identifierCache.value(id);
}
+bool QDeclarativeTypeNameCache::isEmpty() const
+{
+ return identifierCache.isEmpty();
+}
+
+QDeclarativeMetaType::ModuleApiInstance *QDeclarativeTypeNameCache::moduleApi() const
+{
+ return m_moduleApi;
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVETYPENAMECACHE_P_H
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
index a7c0b2cfbe..d628b7065a 100644
--- a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
+++ b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
@@ -63,7 +63,7 @@ struct TypeNameData : public QScriptDeclarativeClass::Object {
QDeclarativeTypeNameScriptClass::QDeclarativeTypeNameScriptClass(QDeclarativeEngine *bindEngine)
: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
- engine(bindEngine), object(0), type(0)
+ engine(bindEngine), object(0), type(0), api(0)
{
}
@@ -95,14 +95,35 @@ QDeclarativeTypeNameScriptClass::queryProperty(Object *obj, const Identifier &na
object = 0;
type = 0;
+ api = 0;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
if (data->typeNamespace) {
-
QDeclarativeTypeNameCache::Data *d = data->typeNamespace->data(name);
if (d && d->type) {
type = d->type;
return QScriptClass::HandlesReadAccess;
+ } else if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = data->typeNamespace->moduleApi()) {
+ if (moduleApi->scriptCallback) {
+ moduleApi->scriptApi = moduleApi->scriptCallback(engine, &ep->scriptEngine);
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ } else if (moduleApi->qobjectCallback) {
+ moduleApi->qobjectApi = moduleApi->qobjectCallback(engine, &ep->scriptEngine);
+ moduleApi->scriptCallback = 0;
+ moduleApi->qobjectCallback = 0;
+ }
+
+ api = moduleApi;
+ if (api->qobjectApi) {
+ return ep->objectClass->queryProperty(api->qobjectApi, name, flags, 0,
+ QDeclarativeObjectScriptClass::SkipAttachedProperties);
+ } else {
+ return QScriptClass::HandlesReadAccess;
+ }
+
+ return 0;
+
} else {
return 0;
}
@@ -147,6 +168,10 @@ QDeclarativeTypeNameScriptClass::property(Object *obj, const Identifier &name)
return Value(scriptEngine, newObject(((TypeNameData *)obj)->object, type, ((TypeNameData *)obj)->mode));
} else if (object) {
return ep->objectClass->property(object, name);
+ } else if (api && api->qobjectApi) {
+ return ep->objectClass->property(api->qobjectApi, name);
+ } else if (api) {
+ return propertyValue(api->scriptApi, name);
} else {
return Value(scriptEngine, enumValue);
}
@@ -154,11 +179,16 @@ QDeclarativeTypeNameScriptClass::property(Object *obj, const Identifier &name)
void QDeclarativeTypeNameScriptClass::setProperty(Object *, const Identifier &n, const QScriptValue &v)
{
- Q_ASSERT(object);
Q_ASSERT(!type);
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- ep->objectClass->setProperty(object, n, v, context());
+ if (api) {
+ Q_ASSERT(api->qobjectApi);
+ ep->objectClass->setProperty(api->qobjectApi, n, v, context());
+ } else {
+ Q_ASSERT(object);
+ ep->objectClass->setProperty(object, n, v, context());
+ }
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass_p.h b/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
index cf7dbc8480..49e1ae809e 100644
--- a/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
+++ b/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
@@ -83,6 +83,7 @@ private:
QDeclarativeEngine *engine;
QObject *object;
QDeclarativeType *type;
+ QDeclarativeMetaType::ModuleApiInstance *api;
quint32 enumValue;
};
diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp
index 781e1b8ea3..6bbc47bcaf 100644
--- a/src/declarative/qml/qdeclarativevme.cpp
+++ b/src/declarative/qml/qdeclarativevme.cpp
@@ -57,8 +57,9 @@
#include "private/qdeclarativevmemetaobject_p.h"
#include "private/qdeclarativebinding_p_p.h"
#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativecompiledbindings_p.h"
+#include "private/qdeclarativev4bindings_p.h"
#include "private/qdeclarativeglobal_p.h"
+#include "private/qdeclarativeglobalscriptclass_p.h"
#include "qdeclarativescriptstring.h"
#include <QStack>
@@ -71,6 +72,7 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdatetime.h>
+#include <QtScript/qscriptvalue.h>
QT_BEGIN_NAMESPACE
@@ -158,7 +160,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
const QList<int> &intData = comp->intData;
const QList<float> &floatData = comp->floatData;
const QList<QDeclarativePropertyCache *> &propertyCaches = comp->propertyCaches;
- const QList<QDeclarativeParser::Object::ScriptBlock> &scripts = comp->scripts;
+ const QList<QDeclarativeScriptData *> &scripts = comp->scripts;
const QList<QUrl> &urls = comp->urls;
QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bindValues;
@@ -186,7 +188,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
if (instr.init.contextCache != -1)
ctxt->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache));
if (instr.init.compiledBinding != -1)
- ctxt->optimizedBindings = new QDeclarativeCompiledBindings(datas.at(instr.init.compiledBinding).constData(), ctxt);
+ ctxt->optimizedBindings = new QDeclarativeV4Bindings(datas.at(instr.init.compiledBinding).constData(), ctxt);
}
break;
@@ -409,6 +411,15 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
}
break;
+ case QDeclarativeInstruction::StoreByteArray:
+ {
+ QObject *target = stack.top();
+ void *a[] = { (void *)&datas.at(instr.storeByteArray.value), 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeByteArray.propertyIndex, a);
+ }
+ break;
+
case QDeclarativeInstruction::StoreUrl:
{
QObject *target = stack.top();
@@ -701,7 +712,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreImportedScript:
{
- ctxt->addImportedScript(scripts.at(instr.storeScript.value));
+ ctxt->importedScripts << run(ctxt, scripts.at(instr.storeScript.value));
}
break;
@@ -1054,5 +1065,68 @@ QDeclarativeCompiledData::TypeReference::createInstance(QDeclarativeContextData
}
}
+QScriptValue QDeclarativeVME::run(QDeclarativeContextData *parentCtxt, QDeclarativeScriptData *script)
+{
+ if (script->m_loaded)
+ return script->m_value;
+
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentCtxt->engine);
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(parentCtxt->engine);
+
+ bool shared = script->pragmas & QDeclarativeParser::Object::ScriptBlock::Shared;
+
+ // Create the script context if required
+ QDeclarativeContextData *ctxt = 0;
+ if (!shared) {
+ ctxt = new QDeclarativeContextData;
+ ctxt->isInternal = true;
+ ctxt->url = script->url;
+
+ // For backward compatibility, if there are no imports, we need to use the
+ // imports from the parent context. See QTBUG-17518.
+ if (!script->importCache->isEmpty()) {
+ ctxt->imports = script->importCache;
+ } else {
+ ctxt->imports = parentCtxt->imports;
+ }
+
+ if (ctxt->imports) {
+ ctxt->imports->addref();
+ }
+
+ ctxt->setParent(parentCtxt, true);
+
+ for (int ii = 0; ii < script->scripts.count(); ++ii)
+ ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
+ }
+
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
+ if (shared) {
+ scriptContext->pushScope(enginePriv->contextClass->newUrlContext(script->url.toString())); // XXX toString()?
+ } else {
+ scriptContext->pushScope(enginePriv->contextClass->newUrlContext(ctxt, 0, script->url.toString()));
+ }
+
+ scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
+ QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
+ scriptContext->pushScope(scope);
+
+ scriptEngine->evaluate(script->m_program);
+
+ if (scriptEngine->hasUncaughtException()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
+ enginePriv->warning(error);
+ }
+
+ scriptEngine->popContext();
+
+ if (shared) {
+ script->m_loaded = true;
+ script->m_value = scope;
+ }
+
+ return scope;
+}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h
index 77c016c1a8..4c010f19d8 100644
--- a/src/declarative/qml/qdeclarativevme_p.h
+++ b/src/declarative/qml/qdeclarativevme_p.h
@@ -62,6 +62,8 @@
QT_BEGIN_NAMESPACE
class QObject;
+class QScriptValue;
+class QDeclarativeScriptData;
class QDeclarativeInstruction;
class QDeclarativeCompiledData;
class QDeclarativeCompiledData;
@@ -103,6 +105,8 @@ public:
QObject *run(QDeclarativeContextData *, QDeclarativeCompiledData *,
int start = -1, int count = -1,
const QBitField & = QBitField());
+ QScriptValue run(QDeclarativeContextData *, QDeclarativeScriptData *);
+
void runDeferred(QObject *);
bool isError() const;
diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp
index ad1bf0dd3a..6eb74b3bad 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject.cpp
+++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp
@@ -647,6 +647,7 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
return -1; // We can't run the method
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
QScriptValue function = method(id);
@@ -657,10 +658,19 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]);
}
}
+
QScriptValue rv = function.call(ep->objectClass->newQObject(object), args);
+ if (ep->scriptEngine.hasUncaughtException()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(&ep->scriptEngine, error);
+ if (error.isValid()) {
+ ep->warning(error);
+ }
+ }
if (a[0]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv);
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return -1;
}
return -1;
diff --git a/src/declarative/qml/qdeclarativexmlhttprequest.cpp b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
index aefc896f5b..930d345285 100644
--- a/src/declarative/qml/qdeclarativexmlhttprequest.cpp
+++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
@@ -101,6 +101,8 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+namespace {
+
class DocumentImpl;
class NodeImpl
{
@@ -323,6 +325,8 @@ public:
static QScriptValue load(QScriptEngine *engine, const QByteArray &data);
};
+}
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Node)
@@ -1231,6 +1235,18 @@ void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes)
}
}
+static const char *errorToString(QNetworkReply::NetworkError error)
+{
+ int idx = QNetworkReply::staticMetaObject.indexOfEnumerator("NetworkError");
+ if (idx == -1) return "EnumLookupFailed";
+
+ QMetaEnum e = QNetworkReply::staticMetaObject.enumerator(idx);
+
+ const char *name = e.valueToKey(error);
+ if (!name) return "EnumLookupFailed";
+ else return name;
+}
+
void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
@@ -1245,6 +1261,11 @@ void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
m_data.clear();
destroyNetwork();
+ if (xhrDump()) {
+ qWarning().nospace() << "XMLHttpRequest: ERROR " << qPrintable(m_url.toString());
+ qWarning().nospace() << " " << error << " " << errorToString(error) << " " << m_statusText;
+ }
+
if (error == QNetworkReply::ContentAccessDenied ||
error == QNetworkReply::ContentOperationNotPermittedError ||
error == QNetworkReply::ContentNotFoundError ||
diff --git a/src/declarative/qml/qintrusivelist.cpp b/src/declarative/qml/qintrusivelist.cpp
new file mode 100644
index 0000000000..6c27af0777
--- /dev/null
+++ b/src/declarative/qml/qintrusivelist.cpp
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qintrusivelist_p.h"
+
+/*!
+\class QIntrusiveList
+\brief The QIntrusiveList class is a template class that provides a list of objects using static storage.
+\internal
+
+QIntrusiveList creates a linked list of objects. Adding and removing objects from the
+QIntrusiveList is a constant time operation and is very quick. The list performs no memory
+allocations, but does require the objects being added to the list to contain a QIntrusiveListNode
+instance for the list's use. Even so, for small lists QIntrusiveList uses less memory than Qt's
+other list classes.
+
+As QIntrusiveList uses storage inside the objects in the list, each object can only be in one
+list at a time. Objects are inserted by the insert() method. If the object is already
+in a list (including the one it is being inserted into) it is first removed, and then inserted
+at the head of the list. QIntrusiveList is a last-in-first-out list. That is, following an
+insert() the inserted object becomes the list's first() object.
+
+\code
+struct MyObject {
+ MyObject(int value) : value(value) {}
+
+ int value;
+ QIntrusiveListNode node;
+};
+typedef QIntrusiveList<MyObject, &MyObject::node> MyObjectList;
+
+void foo() {
+ MyObjectList list;
+
+ MyObject m0(0);
+ MyObject m1(1);
+ MyObject m2(2);
+
+ list.insert(&m0);
+ list.insert(&m1);
+ list.insert(&m2);
+
+ // QIntrusiveList is LIFO, so will print: 2... 1... 0...
+ for (MyObjectList::iterator iter = list.begin(); iter != list.end(); ++iter) {
+ qWarning() << iter->value;
+ }
+}
+\endcode
+*/
+
+
+/*!
+\fn QIntrusiveList::QIntrusiveList();
+
+Construct an empty list.
+*/
+
+/*!
+\fn QIntrusiveList::~QIntrusiveList();
+
+Destroy the list. All entries are removed.
+*/
+
+/*!
+\fn void QIntrusiveList::insert(N *object);
+
+Insert \a object into the list. If \a object is a member of this, or another list, it will be
+removed and inserted at the head of this list.
+*/
+
+/*!
+\fn void QIntrusiveList::remove(N *object);
+
+Remove \a object from the list. \a object must not be null.
+*/
+
+/*!
+\fn N *QIntrusiveList::first() const
+
+Returns the first entry in this list, or null if the list is empty.
+*/
+
+/*!
+\fn N *QIntrusiveList::next(N *current)
+
+Returns the next object after \a current, or null if \a current is the last object. \a current cannot be null.
+*/
+
+/*!
+\fn iterator QIntrusiveList::begin()
+
+Returns an STL-style interator pointing to the first item in the list.
+
+\sa end()
+*/
+
+/*!
+\fn iterator QIntrusiveList::end()
+
+Returns an STL-style iterator pointing to the imaginary item after the last item in the list.
+
+\sa begin()
+*/
+
+/*!
+iterator &QInplacelist::iterator::erase()
+
+Remove the current object from the list, and return an iterator to the next element.
+*/
+
+
+/*!
+\fn QIntrusiveListNode::QIntrusiveListNode()
+
+Create a QIntrusiveListNode.
+*/
+
+/*!
+\fn QIntrusiveListNode::~QIntrusiveListNode()
+
+Destroy the QIntrusiveListNode. If the node is in a list, it is removed.
+*/
+
+/*!
+\fn void QIntrusiveListNode::remove()
+
+If in a list, remove this node otherwise do nothing.
+*/
+
+/*!
+\fn bool QIntrusiveListNode::isInList() const
+
+Returns true if this node is in a list, false otherwise.
+*/
+
diff --git a/src/declarative/qml/qintrusivelist_p.h b/src/declarative/qml/qintrusivelist_p.h
new file mode 100644
index 0000000000..459d051d07
--- /dev/null
+++ b/src/declarative/qml/qintrusivelist_p.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QINTRUSIVELIST_P_H
+#define QINTRUSIVELIST_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 <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIntrusiveListNode;
+template<class N, QIntrusiveListNode N::*member>
+class QIntrusiveList
+{
+public:
+ inline QIntrusiveList();
+ inline ~QIntrusiveList();
+
+ inline void insert(N *n);
+ inline void remove(N *n);
+
+ class iterator {
+ public:
+ inline iterator();
+ inline iterator(N *value);
+
+ inline N *operator*() const;
+ inline N *operator->() const;
+ inline bool operator==(const iterator &other) const;
+ inline bool operator!=(const iterator &other) const;
+ inline iterator &operator++();
+
+ inline iterator &erase();
+
+ private:
+ N *_value;
+ };
+ typedef iterator Iterator;
+
+ inline N *first() const;
+ static inline N *next(N *current);
+
+ inline iterator begin();
+ inline iterator end();
+
+private:
+ static inline N *nodeToN(QIntrusiveListNode *node);
+
+ QIntrusiveListNode *__first;
+};
+
+class QIntrusiveListNode
+{
+public:
+ inline QIntrusiveListNode();
+ inline ~QIntrusiveListNode();
+
+ inline void remove();
+ inline bool isInList() const;
+
+ QIntrusiveListNode *_next;
+ QIntrusiveListNode**_prev;
+};
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::iterator::iterator()
+: _value(0)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::iterator::iterator(N *value)
+: _value(value)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::iterator::operator*() const
+{
+ return _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::iterator::operator->() const
+{
+ return _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::iterator::operator==(const iterator &other) const
+{
+ return other._value == _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::iterator::operator!=(const iterator &other) const
+{
+ return other._value != _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::operator++()
+{
+ _value = QIntrusiveList<N, member>::next(_value);
+ return *this;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::erase()
+{
+ N *old = _value;
+ _value = QIntrusiveList<N, member>::next(_value);
+ (old->*member).remove();
+ return *this;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::QIntrusiveList()
+: __first(0)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::~QIntrusiveList()
+{
+ while (__first) __first->remove();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+void QIntrusiveList<N, member>::insert(N *n)
+{
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
+
+ nnode->_next = __first;
+ if (nnode->_next) nnode->_next->_prev = &nnode->_next;
+ __first = nnode;
+ nnode->_prev = &__first;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+void QIntrusiveList<N, member>::remove(N *n)
+{
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::first() const
+{
+ return __first?nodeToN(__first):0;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::next(N *current)
+{
+ QIntrusiveListNode *nextnode = (current->*member)._next;
+ N *nextstruct = nextnode?nodeToN(nextnode):0;
+ return nextstruct;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::begin()
+{
+ return __first?iterator(nodeToN(__first)):iterator();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end()
+{
+ return iterator();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node)
+{
+ return (N *)((char *)node - ((char *)&(((N *)0)->*member) - (char *)0));
+}
+
+QIntrusiveListNode::QIntrusiveListNode()
+: _next(0), _prev(0)
+{
+}
+
+QIntrusiveListNode::~QIntrusiveListNode()
+{
+ remove();
+}
+
+void QIntrusiveListNode::remove()
+{
+ if (_prev) *_prev = _next;
+ if (_next) _next->_prev = _prev;
+ _prev = 0;
+ _next = 0;
+}
+
+bool QIntrusiveListNode::isInList() const
+{
+ return _prev != 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QINTRUSIVELIST_P_H
diff --git a/src/declarative/qml/qmetaobjectbuilder.cpp b/src/declarative/qml/qmetaobjectbuilder.cpp
index dc941e2601..a63656bc28 100644
--- a/src/declarative/qml/qmetaobjectbuilder.cpp
+++ b/src/declarative/qml/qmetaobjectbuilder.cpp
@@ -101,7 +101,7 @@ bool isVariantType(const char* type)
return qvariant_nameToType(type) != 0;
}
-// copied from qmetaobject.cpp
+// copied from qmetaobject_p.h
// do not touch without touching the moc as well
enum PropertyFlags {
Invalid = 0x00000000,
@@ -111,6 +111,8 @@ enum PropertyFlags {
EnumOrFlag = 0x00000008,
StdCppSet = 0x00000100,
// Override = 0x00000200,
+ Constant = 0x00000400,
+ Final = 0x00000800,
Designable = 0x00001000,
ResolveDesignable = 0x00002000,
Scriptable = 0x00004000,
@@ -618,6 +620,8 @@ QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& protot
property.setUser(prototype.isUser());
property.setStdCppSet(prototype.hasStdCppSet());
property.setEnumOrFlag(prototype.isEnumType());
+ property.setConstant(prototype.isConstant());
+ property.setFinal(prototype.isFinal());
if (prototype.hasNotifySignal()) {
// Find an existing method for the notify signal, or add a new one.
QMetaMethod method = prototype.notifySignal();
@@ -2278,6 +2282,32 @@ bool QMetaPropertyBuilder::isEnumOrFlag() const
}
/*!
+ Returns true if the property is constant; otherwise returns false.
+ The default value is false.
+*/
+bool QMetaPropertyBuilder::isConstant() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Constant);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is final; otherwise returns false.
+ The default value is false.
+*/
+bool QMetaPropertyBuilder::isFinal() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Final);
+ else
+ return false;
+}
+
+/*!
Sets this property to readable if \a value is true.
\sa isReadable(), setWritable()
@@ -2401,6 +2431,31 @@ void QMetaPropertyBuilder::setEnumOrFlag(bool value)
}
/*!
+ Sets the \c CONSTANT flag on this property to \a value.
+
+ \sa isConstant()
+*/
+void QMetaPropertyBuilder::setConstant(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Constant, value);
+}
+
+/*!
+ Sets the \c FINAL flag on this property to \a value.
+
+ \sa isFinal()
+*/
+void QMetaPropertyBuilder::setFinal(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Final, value);
+}
+
+
+/*!
\class QMetaEnumBuilder
\internal
\brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder.
diff --git a/src/declarative/qml/qmetaobjectbuilder_p.h b/src/declarative/qml/qmetaobjectbuilder_p.h
index d7085f8784..335a825be3 100644
--- a/src/declarative/qml/qmetaobjectbuilder_p.h
+++ b/src/declarative/qml/qmetaobjectbuilder_p.h
@@ -258,6 +258,8 @@ public:
bool isUser() const;
bool hasStdCppSet() const;
bool isEnumOrFlag() const;
+ bool isConstant() const;
+ bool isFinal() const;
void setReadable(bool value);
void setWritable(bool value);
@@ -269,6 +271,8 @@ public:
void setUser(bool value);
void setStdCppSet(bool value);
void setEnumOrFlag(bool value);
+ void setConstant(bool value);
+ void setFinal(bool value);
private:
const QMetaObjectBuilder *_mobj;
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index bf9e54a986..62c1f97d60 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -18,7 +18,6 @@ SOURCES += \
$$PWD/qdeclarativecompiler.cpp \
$$PWD/qdeclarativecompileddata.cpp \
$$PWD/qdeclarativeboundsignal.cpp \
- $$PWD/qdeclarativedom.cpp \
$$PWD/qdeclarativerefcount.cpp \
$$PWD/qdeclarativemetatype.cpp \
$$PWD/qdeclarativestringconverters.cpp \
@@ -30,7 +29,6 @@ SOURCES += \
$$PWD/qdeclarativeenginedebug.cpp \
$$PWD/qdeclarativerewrite.cpp \
$$PWD/qdeclarativevaluetype.cpp \
- $$PWD/qdeclarativecompiledbindings.cpp \
$$PWD/qdeclarativefastproperties.cpp \
$$PWD/qdeclarativexmlhttprequest.cpp \
$$PWD/qdeclarativesqldatabase.cpp \
@@ -44,6 +42,7 @@ SOURCES += \
$$PWD/qdeclarativetypenamecache.cpp \
$$PWD/qdeclarativescriptstring.cpp \
$$PWD/qdeclarativeobjectscriptclass.cpp \
+ $$PWD/qdeclarativescarceresourcescriptclass.cpp \
$$PWD/qdeclarativecontextscriptclass.cpp \
$$PWD/qdeclarativeglobalscriptclass.cpp \
$$PWD/qdeclarativevaluetypescriptclass.cpp \
@@ -56,7 +55,8 @@ SOURCES += \
$$PWD/qdeclarativeextensionplugin.cpp \
$$PWD/qdeclarativeimport.cpp \
$$PWD/qdeclarativelist.cpp \
- $$PWD/qperformancetimer.cpp
+ $$PWD/qperformancetimer.cpp \
+ $$PWD/qintrusivelist.cpp \
HEADERS += \
$$PWD/qdeclarativeparser_p.h \
@@ -81,8 +81,6 @@ HEADERS += \
$$PWD/qdeclarativeengine_p.h \
$$PWD/qdeclarativeexpression_p.h \
$$PWD/qdeclarativeprivate.h \
- $$PWD/qdeclarativedom_p.h \
- $$PWD/qdeclarativedom_p_p.h \
$$PWD/qdeclarativerefcount_p.h \
$$PWD/qdeclarativemetatype_p.h \
$$PWD/qdeclarativeengine.h \
@@ -104,7 +102,6 @@ HEADERS += \
$$PWD/qpodvector_p.h \
$$PWD/qbitfield_p.h \
$$PWD/qdeclarativevaluetype_p.h \
- $$PWD/qdeclarativecompiledbindings_p.h \
$$PWD/qdeclarativefastproperties_p.h \
$$PWD/qdeclarativexmlhttprequest_p.h \
$$PWD/qdeclarativesqldatabase_p.h \
@@ -118,6 +115,7 @@ HEADERS += \
$$PWD/qdeclarativetypenamecache_p.h \
$$PWD/qdeclarativescriptstring.h \
$$PWD/qdeclarativeobjectscriptclass_p.h \
+ $$PWD/qdeclarativescarceresourcescriptclass_p.h \
$$PWD/qdeclarativecontextscriptclass_p.h \
$$PWD/qdeclarativeglobalscriptclass_p.h \
$$PWD/qdeclarativevaluetypescriptclass_p.h \
@@ -131,11 +129,13 @@ HEADERS += \
$$PWD/qdeclarativeextensioninterface.h \
$$PWD/qdeclarativeimport_p.h \
$$PWD/qdeclarativeextensionplugin.h \
- $$PWD/qperformancetimer_p.h
+ $$PWD/qperformancetimer_p.h \
+ $$PWD/qintrusivelist_p.h \
QT += sql
include(parser/parser.pri)
include(rewriter/rewriter.pri)
+include(v4/v4.pri)
# mirrors logic in corelib/kernel/kernel.pri
unix:!symbian: contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri)
diff --git a/src/declarative/qml/v4/qdeclarativev4bindings.cpp b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
new file mode 100644
index 0000000000..80c7a68697
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
@@ -0,0 +1,1530 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define REGISTER_CLEANUP_DEBUG
+
+#include "private/qdeclarativev4bindings_p.h"
+#include "private/qdeclarativev4program_p.h"
+#include "private/qdeclarativev4compiler_p.h"
+
+#include <private/qdeclarativefastproperties_p.h>
+#include <private/qdeclarativedebugtrace_p.h>
+#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
+#include <private/qsganchors_p_p.h> // For AnchorLine
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qnumeric.h>
+#include <QtCore/qmath.h>
+#include <math.h> // ::fmod
+
+QT_BEGIN_NAMESPACE
+
+using namespace QDeclarativeJS;
+
+namespace {
+struct Register {
+ typedef QDeclarativeRegisterType Type;
+
+ void setUndefined() { dataType = UndefinedType; }
+ void setNaN() { setqreal(qSNaN()); }
+ bool isUndefined() const { return dataType == UndefinedType; }
+
+ void setQObject(QObject *o) { *((QObject **)data) = o; dataType = QObjectStarType; }
+ QObject *getQObject() const { return *((QObject **)data); }
+
+ void setqreal(qreal v) { *((qreal *)data) = v; dataType = QRealType; }
+ qreal getqreal() const { return *((qreal *)data); }
+ qreal &getqrealref() const { return *((qreal *)data); }
+
+ void setint(int v) { *((int *)data) = v; dataType = IntType; }
+ int getint() const { return *((int *)data); }
+ int &getintref() const { return *((int *)data); }
+
+ void setbool(bool v) { *((bool *)data) = v; dataType = BoolType; }
+ bool getbool() const { return *((bool *)data); }
+ bool &getboolref() const { return *((bool *)data); }
+
+ QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
+ QString *getstringptr() { return (QString *)typeDataPtr(); }
+ QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
+ const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
+ const QString *getstringptr() const { return (QString *)typeDataPtr(); }
+ const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
+
+ void *typeDataPtr() { return (void *)&data; }
+ void *typeMemory() { return (void *)data; }
+ const void *typeDataPtr() const { return (void *)&data; }
+ const void *typeMemory() const { return (void *)data; }
+
+ Type gettype() const { return dataType; }
+ void settype(Type t) { dataType = t; }
+
+ // int type; // Optional type
+
+ Type dataType; // Type of data
+ void *data[2]; // Object stored here
+
+ inline void cleanup();
+ inline void cleanupString();
+ inline void cleanupUrl();
+ inline void cleanupVariant();
+
+ inline void copy(const Register &other);
+ inline void init(Type type);
+#ifdef REGISTER_CLEANUP_DEBUG
+ Register() {
+ type = 0;
+ }
+
+ ~Register() {
+ if (dataType >= FirstCleanupType)
+ qWarning("Register leaked of type %d", dataType);
+ }
+#endif
+};
+
+void Register::cleanup()
+{
+ if (dataType >= FirstCleanupType) {
+ if (dataType == QStringType) {
+ getstringptr()->~QString();
+ } else if (dataType == QUrlType) {
+ geturlptr()->~QUrl();
+ } else if (dataType == QVariantType) {
+ getvariantptr()->~QVariant();
+ }
+ }
+ setUndefined();
+}
+
+void Register::cleanupString()
+{
+ getstringptr()->~QString();
+ setUndefined();
+}
+
+void Register::cleanupUrl()
+{
+ geturlptr()->~QUrl();
+ setUndefined();
+}
+
+void Register::cleanupVariant()
+{
+ getvariantptr()->~QVariant();
+ setUndefined();
+}
+
+void Register::copy(const Register &other)
+{
+ *this = other;
+ if (other.dataType >= FirstCleanupType) {
+ if (other.dataType == QStringType)
+ new (getstringptr()) QString(*other.getstringptr());
+ else if (other.dataType == QUrlType)
+ new (geturlptr()) QUrl(*other.geturlptr());
+ else if (other.dataType == QVariantType)
+ new (getvariantptr()) QVariant(*other.getvariantptr());
+ }
+}
+
+void Register::init(Type type)
+{
+ dataType = type;
+ if (dataType >= FirstCleanupType) {
+ if (dataType == QStringType)
+ new (getstringptr()) QString();
+ else if (dataType == QUrlType)
+ new (geturlptr()) QUrl();
+ else if (dataType == QVariantType)
+ new (getvariantptr()) QVariant();
+ }
+}
+
+} // end of anonymous namespace
+
+class QDeclarativeV4BindingsPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeV4Bindings)
+
+public:
+ QDeclarativeV4BindingsPrivate();
+ virtual ~QDeclarativeV4BindingsPrivate();
+
+ struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
+ Binding() : enabled(false), updating(0), property(0),
+ scope(0), target(0), executedBlocks(0), parent(0) {}
+
+ // Inherited from QDeclarativeAbstractBinding
+ virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
+ virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
+ virtual void destroy();
+
+ int index:30;
+ bool enabled:1;
+ bool updating:1;
+ int property;
+ QObject *scope;
+ QObject *target;
+ quint32 executedBlocks;
+
+ QDeclarativeV4BindingsPrivate *parent;
+ };
+
+ typedef QDeclarativeNotifierEndpoint Subscription;
+ Subscription *subscriptions;
+ QScriptDeclarativeClass::PersistentIdentifier *identifiers;
+
+ void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
+
+ QDeclarativeV4Program *program;
+ Binding *bindings;
+
+ static int methodCount;
+
+ void init();
+ void run(int instr, quint32 &executedBlocks, QDeclarativeContextData *context,
+ QDeclarativeDelayedError *error, QObject *scope, QObject *output,
+ QDeclarativePropertyPrivate::WriteFlags storeFlags
+#ifdef QML_THREADED_INTERPRETER
+ , void ***decode_instr = 0
+#endif
+ );
+
+
+ inline void unsubscribe(int subIndex);
+ inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
+ inline void subscribe(QObject *o, int notifyIndex, int subIndex);
+
+ inline static qint32 toInt32(qsreal n);
+ static const qsreal D32;
+ static quint32 toUint32(qsreal n);
+};
+
+QDeclarativeV4BindingsPrivate::QDeclarativeV4BindingsPrivate()
+: subscriptions(0), identifiers(0), program(0), bindings(0)
+{
+}
+
+QDeclarativeV4BindingsPrivate::~QDeclarativeV4BindingsPrivate()
+{
+ delete [] subscriptions; subscriptions = 0;
+ delete [] identifiers; identifiers = 0;
+}
+
+int QDeclarativeV4BindingsPrivate::methodCount = -1;
+
+QDeclarativeV4Bindings::QDeclarativeV4Bindings(const char *program, QDeclarativeContextData *context)
+: QObject(*(new QDeclarativeV4BindingsPrivate))
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ if (d->methodCount == -1)
+ d->methodCount = QDeclarativeV4Bindings::staticMetaObject.methodCount();
+
+ d->program = (QDeclarativeV4Program *)program;
+
+ if (program) {
+ d->init();
+
+ QDeclarativeAbstractExpression::setContext(context);
+ }
+}
+
+QDeclarativeV4Bindings::~QDeclarativeV4Bindings()
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ delete [] d->bindings;
+}
+
+QDeclarativeAbstractBinding *QDeclarativeV4Bindings::configBinding(int index, QObject *target,
+ QObject *scope, int property)
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ QDeclarativeV4BindingsPrivate::Binding *rv = d->bindings + index;
+
+ rv->index = index;
+ rv->property = property;
+ rv->target = target;
+ rv->scope = scope;
+ rv->parent = d;
+
+ addref(); // This is decremented in Binding::destroy()
+
+ return rv;
+}
+
+void QDeclarativeV4BindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ if (enabled != e) {
+ enabled = e;
+
+ if (e) update(flags);
+ }
+}
+
+void QDeclarativeV4BindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
+ parent->run(this, flags);
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
+}
+
+void QDeclarativeV4BindingsPrivate::Binding::destroy()
+{
+ enabled = false;
+ removeFromObject();
+ clear();
+ parent->q_func()->release();
+}
+
+int QDeclarativeV4Bindings::qt_metacall(QMetaObject::Call c, int id, void **)
+{
+ Q_D(QDeclarativeV4Bindings);
+
+ if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
+ id -= d->methodCount;
+
+ QDeclarativeV4Program::BindingReferenceList *list = d->program->signalTable(id);
+
+ for (quint32 ii = 0; ii < list->count; ++ii) {
+ QDeclarativeV4Program::BindingReference *bindingRef = list->bindings + ii;
+
+ QDeclarativeV4BindingsPrivate::Binding *binding = d->bindings + bindingRef->binding;
+ if (binding->executedBlocks & bindingRef->blockMask)
+ d->run(binding, QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+ }
+ return -1;
+}
+
+void QDeclarativeV4BindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+ if (!binding->enabled)
+ return;
+
+ QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
+ if (!context || !context->isValid())
+ return;
+
+ if (binding->updating) {
+ QString name;
+ if (binding->property & 0xFFFF0000) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
+
+ QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
+ Q_ASSERT(vt);
+
+ name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
+ name.append(QLatin1String("."));
+ name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
+ } else {
+ name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
+ }
+ qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeV4Bindings", "Binding loop detected for property \"%1\"").arg(name);
+ return;
+ }
+
+ binding->updating = true;
+ if (binding->property & 0xFFFF0000) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
+
+ QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
+ Q_ASSERT(vt);
+ vt->read(binding->target, binding->property & 0xFFFF);
+
+ QObject *target = vt;
+ run(binding->index, binding->executedBlocks, context, binding, binding->scope, target, flags);
+
+ vt->write(binding->target, binding->property & 0xFFFF, flags);
+ } else {
+ run(binding->index, binding->executedBlocks, context, binding, binding->scope, binding->target, flags);
+ }
+ binding->updating = false;
+}
+
+
+void QDeclarativeV4BindingsPrivate::unsubscribe(int subIndex)
+{
+ QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+ sub->disconnect();
+}
+
+void QDeclarativeV4BindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+ unsubscribe(subIndex);
+
+ if (p->idValues[idIndex]) {
+ QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+ sub->target = q;
+ sub->targetMethod = methodCount + subIndex;
+ sub->connect(&p->idValues[idIndex].bindings);
+ }
+}
+
+void QDeclarativeV4BindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+ QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+ sub->target = q;
+ sub->targetMethod = methodCount + subIndex;
+ if (o)
+ sub->connect(o, notifyIndex);
+ else
+ sub->disconnect();
+}
+
+// Conversion functions - these MUST match the QtScript expression path
+inline static qreal toReal(Register *reg, int type, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ if (type == QMetaType::QReal) {
+ return reg->getqreal();
+ } else if (type == qMetaTypeId<QVariant>()) {
+ return reg->getvariantptr()->toReal();
+ } else {
+ if (ok) *ok = false;
+ return 0;
+ }
+}
+
+inline static QString toString(Register *reg, int type, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ if (type == QMetaType::QReal) {
+ return QString::number(reg->getqreal());
+ } else if (type == QMetaType::Int) {
+ return QString::number(reg->getint());
+ } else if (type == qMetaTypeId<QVariant>()) {
+ return reg->getvariantptr()->toString();
+ } else if (type == QMetaType::QString) {
+ return *reg->getstringptr();
+ } else {
+ if (ok) *ok = false;
+ return QString();
+ }
+}
+
+inline static bool toBool(Register *reg, int type, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ if (type == QMetaType::Bool) {
+ return reg->getbool();
+ } else if (type == qMetaTypeId<QVariant>()) {
+ return reg->getvariantptr()->toBool();
+ } else {
+ if (ok) *ok = false;
+ return false;
+ }
+}
+
+inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
+{
+ if (ok) *ok = true;
+
+ QUrl base;
+ if (type == qMetaTypeId<QVariant>()) {
+ QVariant *var = reg->getvariantptr();
+ int vt = var->type();
+ if (vt == QVariant::Url) {
+ base = var->toUrl();
+ } else if (vt == QVariant::ByteArray) {
+ base = QUrl(QString::fromUtf8(var->toByteArray()));
+ } else if (vt == QVariant::String) {
+ base = QUrl(var->toString());
+ } else {
+ if (ok) *ok = false;
+ return QUrl();
+ }
+ } else if (type == QMetaType::QString) {
+ base = QUrl(*reg->getstringptr());
+ } else {
+ if (ok) *ok = false;
+ return QUrl();
+ }
+
+ if (!base.isEmpty() && base.isRelative())
+ return context->url.resolved(base);
+ else
+ return base;
+}
+
+static QObject *variantToQObject(const QVariant &value, bool *ok)
+{
+ if (ok) *ok = true;
+
+ if (value.userType() == QMetaType::QObjectStar) {
+ return qvariant_cast<QObject*>(value);
+ } else {
+ if (ok) *ok = false;
+ return 0;
+ }
+}
+
+void QDeclarativeV4BindingsPrivate::init()
+{
+ if (program->subscriptions)
+ subscriptions = new QDeclarativeV4BindingsPrivate::Subscription[program->subscriptions];
+ if (program->identifiers)
+ identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
+
+ bindings = new QDeclarativeV4BindingsPrivate::Binding[program->bindings];
+}
+
+static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
+{
+ QVariant qtscript = qtscriptRaw;
+
+ if (qtscript.userType() == v4.userType()) {
+ } else if (qtscript.canConvert((QVariant::Type)v4.userType())) {
+ qtscript.convert((QVariant::Type)v4.userType());
+ } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
+ qtscript = qVariantFromValue<QObject *>(0);
+ } else {
+ return false;
+ }
+
+ int type = qtscript.userType();
+
+ if (type == qMetaTypeId<QDeclarativeAnchorLine>()) {
+ QDeclarativeAnchorLine la = qvariant_cast<QDeclarativeAnchorLine>(qtscript);
+ QDeclarativeAnchorLine ra = qvariant_cast<QDeclarativeAnchorLine>(v4);
+
+ return la == ra;
+ } else if (type == qMetaTypeId<QSGAnchorLine>()) {
+ QSGAnchorLine la = qvariant_cast<QSGAnchorLine>(qtscript);
+ QSGAnchorLine ra = qvariant_cast<QSGAnchorLine>(v4);
+
+ return la == ra;
+ } else if (type == QMetaType::Double) {
+
+ double la = qvariant_cast<double>(qtscript);
+ double lr = qvariant_cast<double>(v4);
+
+ return la == lr || (qIsNaN(la) && qIsNaN(lr));
+
+ } else if (type == QMetaType::Float) {
+
+ float la = qvariant_cast<float>(qtscript);
+ float lr = qvariant_cast<float>(v4);
+
+ return la == lr || (qIsNaN(la) && qIsNaN(lr));
+
+ } else {
+ return qtscript == v4;
+ }
+}
+
+QByteArray testResultToString(const QVariant &result, bool undefined)
+{
+ if (undefined) {
+ return "undefined";
+ } else {
+ QString rv;
+ QDebug d(&rv);
+ d << result;
+ return rv.toUtf8();
+ }
+}
+
+static void testBindingResult(const QString &binding, int line, int column,
+ QDeclarativeContextData *context, QObject *scope,
+ const Register &result, int resultType)
+{
+ QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
+ bool isUndefined = false;
+ QVariant value = expression.evaluate(&isUndefined);
+
+ bool iserror = false;
+ QByteArray qtscriptResult;
+ QByteArray v4Result;
+
+ if (expression.hasError()) {
+ iserror = true;
+ qtscriptResult = "exception";
+ } else {
+ qtscriptResult = testResultToString(value, isUndefined);
+ }
+
+ if (isUndefined && result.isUndefined()) {
+ return;
+ } else if(isUndefined != result.isUndefined()) {
+ iserror = true;
+ }
+
+ QVariant v4value;
+ if (!result.isUndefined()) {
+ switch (resultType) {
+ case QMetaType::QString:
+ v4value = *result.getstringptr();
+ break;
+ case QMetaType::QUrl:
+ v4value = *result.geturlptr();
+ break;
+ case QMetaType::QObjectStar:
+ v4value = qVariantFromValue<QObject *>(result.getQObject());
+ break;
+ case QMetaType::Bool:
+ v4value = result.getbool();
+ break;
+ case QMetaType::Int:
+ v4value = result.getint();
+ break;
+ case QMetaType::QReal:
+ v4value = result.getqreal();
+ break;
+ default:
+ if (resultType == qMetaTypeId<QDeclarativeAnchorLine>()) {
+ v4value = qVariantFromValue<QDeclarativeAnchorLine>(*(QDeclarativeAnchorLine *)result.typeDataPtr());
+ } else if (resultType == qMetaTypeId<QSGAnchorLine>()) {
+ v4value = qVariantFromValue<QSGAnchorLine>(*(QSGAnchorLine *)result.typeDataPtr());
+ } else {
+ iserror = true;
+ v4Result = "Unknown V4 type";
+ }
+ }
+ }
+ if (v4Result.isEmpty())
+ v4Result = testResultToString(v4value, result.isUndefined());
+
+ if (!testCompareVariants(value, v4value))
+ iserror = true;
+
+ if (iserror) {
+ qWarning().nospace() << "QDeclarativeV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
+
+ qWarning().nospace() << " Binding: " << binding;
+ qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
+ qWarning().nospace() << " V4: " << v4Result.constData();
+ }
+}
+
+static void testBindingException(const QString &binding, int line, int column,
+ QDeclarativeContextData *context, QObject *scope)
+{
+ QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
+ bool isUndefined = false;
+ QVariant value = expression.evaluate(&isUndefined);
+
+ if (!expression.hasError()) {
+ QByteArray qtscriptResult = testResultToString(value, isUndefined);
+ qWarning().nospace() << "QDeclarativeV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
+ qWarning().nospace() << " Binding: " << binding;
+ qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
+ qWarning().nospace() << " V4: exception";
+ }
+}
+
+static void throwException(int id, QDeclarativeDelayedError *error,
+ QDeclarativeV4Program *program, QDeclarativeContextData *context,
+ const QString &description = QString())
+{
+ error->error.setUrl(context->url);
+ if (description.isEmpty())
+ error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
+ else
+ error->error.setDescription(description);
+ if (id != 0xFF) {
+ quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id);
+ error->error.setLine((e >> 32) & 0xFFFFFFFF);
+ error->error.setColumn(e & 0xFFFFFFFF);
+ } else {
+ error->error.setLine(-1);
+ error->error.setColumn(-1);
+ }
+ if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
+ QDeclarativeEnginePrivate::warning(context->engine, error->error);
+}
+
+const qsreal QDeclarativeV4BindingsPrivate::D32 = 4294967296.0;
+
+qint32 QDeclarativeV4BindingsPrivate::toInt32(qsreal n)
+{
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ double sign = (n < 0) ? -1.0 : 1.0;
+ qsreal abs_n = fabs(n);
+
+ n = ::fmod(sign * ::floor(abs_n), D32);
+ const double D31 = D32 / 2.0;
+
+ if (sign == -1 && n < -D31)
+ n += D32;
+
+ else if (sign != -1 && n >= D31)
+ n -= D32;
+
+ return qint32 (n);
+}
+
+inline quint32 QDeclarativeV4BindingsPrivate::toUint32(qsreal n)
+{
+ if (qIsNaN(n) || qIsInf(n) || (n == 0))
+ return 0;
+
+ double sign = (n < 0) ? -1.0 : 1.0;
+ qsreal abs_n = fabs(n);
+
+ n = ::fmod(sign * ::floor(abs_n), D32);
+
+ if (n < 0)
+ n += D32;
+
+ return quint32 (n);
+}
+
+#define THROW_EXCEPTION_STR(id, str) { \
+ if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
+ throwException((id), error, program, context, (str)); \
+ goto exceptionExit; \
+}
+
+#define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
+
+#define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
+#define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
+
+#define STRING_REGISTER(reg) { \
+ registers[(reg)].settype(QStringType); \
+ MARK_REGISTER(reg); \
+}
+
+#define URL_REGISTER(reg) { \
+ registers[(reg)].settype(QUrlType); \
+ MARK_REGISTER(reg); \
+}
+
+#define VARIANT_REGISTER(reg) { \
+ registers[(reg)].settype(QVariantType); \
+ MARK_REGISTER(reg); \
+}
+
+#ifdef QML_THREADED_INTERPRETER
+void **QDeclarativeV4Bindings::getDecodeInstrTable()
+{
+ static void **decode_instr;
+ if (!decode_instr) {
+ QDeclarativeV4Bindings dummy(0, 0);
+ quint32 executedBlocks = 0;
+ dummy.d_func()->run(0, executedBlocks, 0, 0, 0, 0, QDeclarativePropertyPrivate::BypassInterceptor, &decode_instr);
+ }
+ return decode_instr;
+}
+#endif
+
+void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
+ QDeclarativeContextData *context, QDeclarativeDelayedError *error,
+ QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags
+#ifdef QML_THREADED_INTERPRETER
+ ,void ***table
+#endif
+ )
+{
+ Q_Q(QDeclarativeV4Bindings);
+
+#ifdef QML_THREADED_INTERPRETER
+ if (table) {
+ static void *decode_instr[] = {
+ FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
+ };
+
+ *table = decode_instr;
+ return;
+ }
+#endif
+
+
+ error->removeError();
+
+ Register registers[32];
+ quint32 cleanupRegisterMask = 0;
+
+ executedBlocks = 0;
+
+ QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
+ const char *code = program->instructions();
+ code += instrIndex * QML_INSTR_SIZE(Jump, jump);
+ const Instr *instr = (const Instr *) code;
+
+ const char *data = program->data();
+
+ QString *testBindingSource = 0;
+ bool testBinding = false;
+ int bindingLine = 0;
+ int bindingColumn = 0;
+
+#ifdef QML_THREADED_INTERPRETER
+ goto *instr->common.code;
+#else
+ for (;;) {
+ switch (instr->common.type) {
+#endif
+
+ QML_BEGIN_INSTR(Noop, common)
+ QML_END_INSTR(Noop, common)
+
+ QML_BEGIN_INSTR(BindingId, id)
+ bindingLine = instr->id.line;
+ bindingColumn = instr->id.column;
+ QML_END_INSTR(BindingId, id)
+
+ QML_BEGIN_INSTR(SubscribeId, subscribeop)
+ subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
+ QML_END_INSTR(SubscribeId, subscribeop)
+
+ QML_BEGIN_INSTR(Subscribe, subscribeop)
+ {
+ QObject *o = 0;
+ const Register &object = registers[instr->subscribeop.reg];
+ if (!object.isUndefined()) o = object.getQObject();
+ subscribe(o, instr->subscribeop.index, instr->subscribeop.offset);
+ }
+ QML_END_INSTR(Subscribe, subscribeop)
+
+ QML_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
+ {
+ Register &reg = registers[instr->fetchAndSubscribe.reg];
+
+ if (reg.isUndefined())
+ THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
+
+ QObject *object = reg.getQObject();
+ if (!object) {
+ reg.setUndefined();
+ } else {
+ int subIdx = instr->fetchAndSubscribe.subscription;
+ QDeclarativeV4BindingsPrivate::Subscription *sub = 0;
+ if (subIdx != -1) {
+ sub = (subscriptions + subIdx);
+ sub->target = q;
+ sub->targetMethod = methodCount + subIdx;
+ }
+ reg.init((Register::Type)instr->fetchAndSubscribe.valueType);
+ if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
+ MARK_REGISTER(instr->fetchAndSubscribe.reg);
+ QDeclarativeV4Compiler::fastPropertyAccessor()->accessor(instr->fetchAndSubscribe.function)(object, reg.typeDataPtr(), sub);
+ }
+ }
+ QML_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
+
+ QML_BEGIN_INSTR(LoadId, load)
+ registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
+ QML_END_INSTR(LoadId, load)
+
+ QML_BEGIN_INSTR(LoadScope, load)
+ registers[instr->load.reg].setQObject(scope);
+ QML_END_INSTR(LoadScope, load)
+
+ QML_BEGIN_INSTR(LoadRoot, load)
+ registers[instr->load.reg].setQObject(context->contextObject);
+ QML_END_INSTR(LoadRoot, load)
+
+ QML_BEGIN_INSTR(LoadAttached, attached)
+ {
+ const Register &input = registers[instr->attached.reg];
+ Register &output = registers[instr->attached.output];
+ if (input.isUndefined())
+ THROW_EXCEPTION(instr->attached.exceptionId);
+
+ QObject *object = registers[instr->attached.reg].getQObject();
+ if (!object) {
+ output.setUndefined();
+ } else {
+ QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
+ Q_ASSERT(attached);
+ output.setQObject(attached);
+ }
+ }
+ QML_END_INSTR(LoadAttached, attached)
+
+ QML_BEGIN_INSTR(UnaryNot, unaryop)
+ {
+ registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
+ }
+ QML_END_INSTR(UnaryNot, unaryop)
+
+ QML_BEGIN_INSTR(UnaryMinusReal, unaryop)
+ {
+ registers[instr->unaryop.output].setqreal(-registers[instr->unaryop.src].getqreal());
+ }
+ QML_END_INSTR(UnaryMinusReal, unaryop)
+
+ QML_BEGIN_INSTR(UnaryMinusInt, unaryop)
+ {
+ registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
+ }
+ QML_END_INSTR(UnaryMinusInt, unaryop)
+
+ QML_BEGIN_INSTR(UnaryPlusReal, unaryop)
+ {
+ registers[instr->unaryop.output].setqreal(+registers[instr->unaryop.src].getqreal());
+ }
+ QML_END_INSTR(UnaryPlusReal, unaryop)
+
+ QML_BEGIN_INSTR(UnaryPlusInt, unaryop)
+ {
+ registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
+ }
+ QML_END_INSTR(UnaryPlusInt, unaryop)
+
+ QML_BEGIN_INSTR(ConvertBoolToInt, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(src.getbool());
+ }
+ QML_END_INSTR(ConvertBoolToInt, unaryop)
+
+ QML_BEGIN_INSTR(ConvertBoolToReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(src.getbool());
+ }
+ QML_END_INSTR(ConvertBoolToReal, unaryop)
+
+ QML_BEGIN_INSTR(ConvertBoolToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_END_INSTR(ConvertBoolToString, unaryop)
+
+ QML_BEGIN_INSTR(ConvertIntToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setbool(src.getint());
+ }
+ QML_END_INSTR(ConvertIntToBool, unaryop)
+
+ QML_BEGIN_INSTR(ConvertIntToReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(qreal(src.getint()));
+ }
+ QML_END_INSTR(ConvertIntToReal, unaryop)
+
+ QML_BEGIN_INSTR(ConvertIntToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getstringptr()) QString(QString::number(src.getint()));
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_END_INSTR(ConvertIntToString, unaryop)
+
+ QML_BEGIN_INSTR(ConvertRealToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setbool(src.getqreal() != 0);
+ }
+ QML_END_INSTR(ConvertRealToBool, unaryop)
+
+ QML_BEGIN_INSTR(ConvertRealToInt, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(toInt32(src.getqreal()));
+ }
+ QML_END_INSTR(ConvertRealToInt, unaryop)
+
+ QML_BEGIN_INSTR(ConvertRealToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ new (output.getstringptr()) QString(QString::number(src.getqreal()));
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_END_INSTR(ConvertRealToString, unaryop)
+
+ QML_BEGIN_INSTR(ConvertStringToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
+ // Ideally we should just call the methods in the QScript namespace directly.
+ QScriptValue tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setbool(tmp.toBool());
+ }
+ }
+ QML_END_INSTR(ConvertStringToBool, unaryop)
+
+ QML_BEGIN_INSTR(ConvertStringToInt, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
+ // Ideally we should just call the methods in the QScript namespace directly.
+ QScriptValue tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setint(tmp.toInt32());
+ }
+ }
+ QML_END_INSTR(ConvertStringToInt, unaryop)
+
+ QML_BEGIN_INSTR(ConvertStringToReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
+ // Ideally we should just call the methods in the QScript namespace directly.
+ QScriptValue tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setqreal(tmp.toNumber());
+ }
+ }
+ QML_END_INSTR(ConvertStringToReal, unaryop)
+
+ QML_BEGIN_INSTR(MathSinReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(qSin(src.getqreal()));
+ }
+ QML_END_INSTR(MathSinReal, unaryop)
+
+ QML_BEGIN_INSTR(MathCosReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setqreal(qCos(src.getqreal()));
+ }
+ QML_END_INSTR(MathCosReal, unaryop)
+
+ QML_BEGIN_INSTR(MathRoundReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(qRound(src.getqreal()));
+ }
+ QML_END_INSTR(MathRoundReal, unaryop)
+
+ QML_BEGIN_INSTR(MathFloorReal, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) output.setUndefined();
+ else output.setint(qFloor(src.getqreal()));
+ }
+ QML_END_INSTR(MathFloorReal, unaryop)
+
+ QML_BEGIN_INSTR(MathPIReal, unaryop)
+ {
+ static const qsreal qmlPI = 2.0 * qAsin(1.0);
+ Register &output = registers[instr->unaryop.output];
+ output.setqreal(qmlPI);
+ }
+ QML_END_INSTR(MathPIReal, unaryop)
+
+ QML_BEGIN_INSTR(Real, real_value)
+ registers[instr->real_value.reg].setqreal(instr->real_value.value);
+ QML_END_INSTR(Real, real_value)
+
+ QML_BEGIN_INSTR(Int, int_value)
+ registers[instr->int_value.reg].setint(instr->int_value.value);
+ QML_END_INSTR(Int, int_value)
+
+ QML_BEGIN_INSTR(Bool, bool_value)
+ registers[instr->bool_value.reg].setbool(instr->bool_value.value);
+ QML_END_INSTR(Bool, bool_value)
+
+ QML_BEGIN_INSTR(String, string_value)
+ {
+ Register &output = registers[instr->string_value.reg];
+ QChar *string = (QChar *)(data + instr->string_value.offset);
+ new (output.getstringptr()) QString(string, instr->string_value.length);
+ STRING_REGISTER(instr->string_value.reg);
+ }
+ QML_END_INSTR(String, string_value)
+
+ QML_BEGIN_INSTR(EnableV4Test, string_value)
+ {
+ testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
+ testBinding = true;
+ }
+ QML_END_INSTR(String, string_value)
+
+ QML_BEGIN_INSTR(BitAndInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() &
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(BitAndInt, binaryop)
+
+ QML_BEGIN_INSTR(BitOrInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() |
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(BitAndInt, binaryop)
+
+ QML_BEGIN_INSTR(BitXorInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(BitXorInt, binaryop)
+
+ QML_BEGIN_INSTR(AddReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() +
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(AddReal, binaryop)
+
+ QML_BEGIN_INSTR(AddString, binaryop)
+ {
+ QString &string = *registers[instr->binaryop.output].getstringptr();
+ if (instr->binaryop.output == instr->binaryop.left) {
+ string += registers[instr->binaryop.right].getstringptr();
+ } else {
+ string = *registers[instr->binaryop.left].getstringptr() +
+ *registers[instr->binaryop.right].getstringptr();
+ }
+ }
+ QML_END_INSTR(AddString, binaryop)
+
+ QML_BEGIN_INSTR(SubReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() -
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(SubReal, binaryop)
+
+ QML_BEGIN_INSTR(MulReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() *
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(MulReal, binaryop)
+
+ QML_BEGIN_INSTR(DivReal, binaryop)
+ {
+ registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() /
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(DivReal, binaryop)
+
+ QML_BEGIN_INSTR(ModReal, binaryop)
+ {
+ Register &target = registers[instr->binaryop.output];
+ const Register &left = registers[instr->binaryop.left];
+ const Register &right = registers[instr->binaryop.right];
+ if (QMetaType::QReal == QMetaType::Float)
+ target.setqreal(::fmodf(left.getqreal(), right.getqreal()));
+ else
+ target.setqreal(::fmod(left.getqreal(), right.getqreal()));
+ }
+ QML_END_INSTR(ModInt, binaryop)
+
+ QML_BEGIN_INSTR(LShiftInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() <<
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(LShiftInt, binaryop)
+
+ QML_BEGIN_INSTR(RShiftInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >>
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(RShiftInt, binaryop)
+
+ QML_BEGIN_INSTR(URShiftInt, binaryop)
+ {
+ registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >>
+ registers[instr->binaryop.right].getint());
+ }
+ QML_END_INSTR(URShiftInt, binaryop)
+
+ QML_BEGIN_INSTR(GtReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(GtReal, binaryop)
+
+ QML_BEGIN_INSTR(LtReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(LtReal, binaryop)
+
+ QML_BEGIN_INSTR(GeReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(GeReal, binaryop)
+
+ QML_BEGIN_INSTR(LeReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(LeReal, binaryop)
+
+ QML_BEGIN_INSTR(EqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() ==
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(EqualReal, binaryop)
+
+ QML_BEGIN_INSTR(NotEqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() !=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(NotEqualReal, binaryop)
+
+ QML_BEGIN_INSTR(StrictEqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() ==
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(StrictEqualReal, binaryop)
+
+ QML_BEGIN_INSTR(StrictNotEqualReal, binaryop)
+ {
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() !=
+ registers[instr->binaryop.right].getqreal());
+ }
+ QML_END_INSTR(StrictNotEqualReal, binaryop)
+
+ QML_BEGIN_INSTR(GtString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a > b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(GtString, binaryop)
+
+ QML_BEGIN_INSTR(LtString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a < b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(LtString, binaryop)
+
+ QML_BEGIN_INSTR(GeString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a >= b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(GeString, binaryop)
+
+ QML_BEGIN_INSTR(LeString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a <= b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(LeString, binaryop)
+
+ QML_BEGIN_INSTR(EqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a == b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(EqualString, binaryop)
+
+ QML_BEGIN_INSTR(NotEqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a != b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(NotEqualString, binaryop)
+
+ QML_BEGIN_INSTR(StrictEqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a == b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(StrictEqualString, binaryop)
+
+ QML_BEGIN_INSTR(StrictNotEqualString, binaryop)
+ {
+ const QString &a = *registers[instr->binaryop.left].getstringptr();
+ const QString &b = *registers[instr->binaryop.right].getstringptr();
+ bool result = a != b;
+ if (instr->binaryop.left == instr->binaryop.output) {
+ registers[instr->binaryop.output].cleanupString();
+ MARK_CLEAN_REGISTER(instr->binaryop.output);
+ }
+ registers[instr->binaryop.output].setbool(result);
+ }
+ QML_END_INSTR(StrictNotEqualString, binaryop)
+
+ QML_BEGIN_INSTR(NewString, construct)
+ {
+ Register &output = registers[instr->construct.reg];
+ new (output.getstringptr()) QString;
+ STRING_REGISTER(instr->construct.reg);
+ }
+ QML_END_INSTR(NewString, construct)
+
+ QML_BEGIN_INSTR(NewUrl, construct)
+ {
+ Register &output = registers[instr->construct.reg];
+ new (output.geturlptr()) QUrl;
+ URL_REGISTER(instr->construct.reg);
+ }
+ QML_END_INSTR(NewUrl, construct)
+
+ QML_BEGIN_INSTR(Fetch, fetch)
+ {
+ Register &reg = registers[instr->fetch.reg];
+
+ if (reg.isUndefined())
+ THROW_EXCEPTION(instr->fetch.exceptionId);
+
+ QObject *object = reg.getQObject();
+ if (!object) {
+ THROW_EXCEPTION(instr->fetch.exceptionId);
+ } else {
+ reg.init((Register::Type)instr->fetch.valueType);
+ if (instr->fetch.valueType >= FirstCleanupType)
+ MARK_REGISTER(instr->fetch.reg);
+ void *argv[] = { reg.typeDataPtr(), 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
+ }
+ }
+ QML_END_INSTR(Fetch, fetch)
+
+ QML_BEGIN_INSTR(TestV4Store, storetest)
+ {
+ Register &data = registers[instr->storetest.reg];
+ testBindingResult(*testBindingSource, bindingLine, bindingColumn, context,
+ scope, data, instr->storetest.regType);
+ }
+ QML_END_INSTR(TestV4Store, storetest)
+
+ QML_BEGIN_INSTR(Store, store)
+ {
+ Register &data = registers[instr->store.reg];
+
+ if (data.isUndefined())
+ THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
+
+ int status = -1;
+ void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
+ QMetaObject::metacall(output, QMetaObject::WriteProperty,
+ instr->store.index, argv);
+
+ goto programExit;
+ }
+ QML_END_INSTR(Store, store)
+
+ QML_BEGIN_INSTR(Copy, copy)
+ registers[instr->copy.reg].copy(registers[instr->copy.src]);
+ if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
+ MARK_REGISTER(instr->copy.reg);
+ QML_END_INSTR(Copy, copy)
+
+ QML_BEGIN_INSTR(Jump, jump)
+ if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
+ code += instr->jump.count;
+ QML_END_INSTR(Jump, jump)
+
+ QML_BEGIN_INSTR(BranchTrue, branchop)
+ if (registers[instr->branchop.reg].getbool())
+ code += instr->branchop.offset;
+ QML_END_INSTR(BranchTrue, branchop)
+
+ QML_BEGIN_INSTR(BranchFalse, branchop)
+ if (! registers[instr->branchop.reg].getbool())
+ code += instr->branchop.offset;
+ QML_END_INSTR(BranchFalse, branchop)
+
+ QML_BEGIN_INSTR(Branch, branchop)
+ code += instr->branchop.offset;
+ QML_END_INSTR(Branch, branchop)
+
+ QML_BEGIN_INSTR(Block, blockop)
+ executedBlocks |= instr->blockop.block;
+ QML_END_INSTR(Block, blockop)
+
+ QML_BEGIN_INSTR(InitString, initstring)
+ if (!identifiers[instr->initstring.offset].identifier) {
+ quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
+ QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
+
+ QString str = QString::fromRawData(strdata, len);
+
+ identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
+ }
+ QML_END_INSTR(InitString, initstring)
+
+ QML_BEGIN_INSTR(CleanupRegister, cleanup)
+ registers[instr->cleanup.reg].cleanup();
+ QML_END_INSTR(CleanupRegister, cleanup)
+
+#ifdef QML_THREADED_INTERPRETER
+ // nothing to do
+#else
+ default:
+ qFatal("QDeclarativeV4: Unknown instruction %d encountered.", instr->common.type);
+ break;
+ } // switch
+
+ } // while
+#endif
+
+ Q_ASSERT(!"Unreachable code reached");
+
+programExit:
+exceptionExit:
+ delete testBindingSource;
+
+ int reg = 0;
+ while (cleanupRegisterMask) {
+ if (cleanupRegisterMask & 0x1)
+ registers[reg].cleanup();
+
+ reg++;
+ cleanupRegisterMask >>= 1;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4bindings_p.h b/src/declarative/qml/v4/qdeclarativev4bindings_p.h
new file mode 100644
index 0000000000..9f225b65b6
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4bindings_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4BINDINGS_P_H
+#define QDECLARATIVEV4BINDINGS_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/qdeclarativeexpression_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativev4instruction_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeV4BindingsPrivate;
+class QDeclarativeV4Bindings : public QObject,
+ public QDeclarativeAbstractExpression,
+ public QDeclarativeRefCount
+{
+public:
+ QDeclarativeV4Bindings(const char *program, QDeclarativeContextData *context);
+ virtual ~QDeclarativeV4Bindings();
+
+ QDeclarativeAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property);
+
+#ifdef QML_THREADED_INTERPRETER
+ static void **getDecodeInstrTable();
+#endif
+
+protected:
+ int qt_metacall(QMetaObject::Call, int, void **);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeV4Bindings)
+ Q_DECLARE_PRIVATE(QDeclarativeV4Bindings)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4BINDINGS_P_H
+
diff --git a/src/declarative/qml/v4/qdeclarativev4compiler.cpp b/src/declarative/qml/v4/qdeclarativev4compiler.cpp
new file mode 100644
index 0000000000..a7eecce0c9
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4compiler.cpp
@@ -0,0 +1,1340 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4compiler_p.h"
+#include "qdeclarativev4compiler_p_p.h"
+#include "qdeclarativev4program_p.h"
+#include "qdeclarativev4ir_p.h"
+#include "qdeclarativev4irbuilder_p.h"
+
+#include <private/qdeclarativejsast_p.h>
+#include <private/qdeclarativefastproperties_p.h>
+#include <private/qdeclarativejsengine_p.h>
+#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
+#include <private/qsganchors_p_p.h> // For AnchorLine
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP)
+DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER)
+DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL)
+DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST)
+
+Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties)
+
+static bool qmlBindingsTest = false;
+
+using namespace QDeclarativeJS;
+QDeclarativeV4CompilerPrivate::QDeclarativeV4CompilerPrivate()
+: _function(0) , _block(0) , _discarded(false)
+{
+}
+
+//
+// tracing
+//
+void QDeclarativeV4CompilerPrivate::trace(int line, int column)
+{
+ bytecode.clear();
+
+ this->currentReg = _function->tempCount;
+
+ foreach (IR::BasicBlock *bb, _function->basicBlocks) {
+ if (! bb->isTerminated() && (bb->index + 1) < _function->basicBlocks.size())
+ bb->JUMP(_function->basicBlocks.at(bb->index + 1));
+ }
+
+ QVector<IR::BasicBlock *> blocks;
+ trace(&blocks);
+ currentBlockMask = 0x00000001;
+
+
+ for (int i = 0; i < blocks.size(); ++i) {
+ IR::BasicBlock *block = blocks.at(i);
+ IR::BasicBlock *next = i + 1 < blocks.size() ? blocks.at(i + 1) : 0;
+ if (IR::Stmt *terminator = block->terminator()) {
+ if (IR::CJump *cj = terminator->asCJump()) {
+ if (cj->iffalse != next) {
+ block->i(new IR::Jump(cj->iffalse));
+ }
+ } else if (IR::Jump *j = terminator->asJump()) {
+ if (j->target == next) {
+ delete block->statements.back();
+ block->statements.resize(block->statements.size() - 1);
+ }
+ }
+ }
+
+ block->offset = bytecode.size();
+
+ if (bytecode.isEmpty()) {
+ if (qmlBindingsTest || bindingsDump()) {
+ Instr id;
+ id.common.type = Instr::BindingId;
+ id.id.column = column;
+ id.id.line = line;
+ gen(id);
+ }
+
+ if (qmlBindingsTest) {
+ QString str = expression->expression.asScript();
+ QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
+ int offset = data.count();
+ data += strdata;
+
+ Instr test;
+ test.common.type = Instr::EnableV4Test;
+ test.string_value.reg = 0;
+ test.string_value.offset = offset;
+ test.string_value.length = str.length();
+ gen(test);
+ }
+ }
+
+ bool usic = false;
+ int patchesCount = patches.count();
+ qSwap(usedSubscriptionIdsChanged, usic);
+
+ int blockopIndex = bytecode.size();
+ Instr blockop;
+ blockop.block(currentBlockMask);
+ gen(blockop);
+
+ foreach (IR::Stmt *s, block->statements)
+ s->accept(this);
+
+ qSwap(usedSubscriptionIdsChanged, usic);
+
+ if (usic) {
+ if (currentBlockMask == 0x80000000) {
+ discard();
+ return;
+ }
+ currentBlockMask <<= 1;
+ } else {
+ const int adjust = bytecode.remove(blockopIndex);
+ // Correct patches
+ for (int ii = patchesCount; ii < patches.count(); ++ii)
+ patches[ii].offset -= adjust;
+ }
+ }
+
+#ifdef DEBUG_IR_STRUCTURE
+ IR::IRDump dump;
+ for (int i = 0; i < blocks.size(); ++i) {
+ dump.basicblock(blocks.at(i));
+ }
+#endif
+
+
+ // back patching
+ foreach (const Patch &patch, patches) {
+ Instr &instr = bytecode[patch.offset];
+ instr.branchop.offset = patch.block->offset - patch.offset - instr.size();
+ }
+
+ patches.clear();
+}
+
+void QDeclarativeV4CompilerPrivate::trace(QVector<IR::BasicBlock *> *blocks)
+{
+ QList<IR::BasicBlock *> todo = QList<IR::BasicBlock *>::fromVector(_function->basicBlocks);
+ while (! todo.isEmpty()) {
+ IR::BasicBlock *block = todo.takeFirst();
+
+ while (! blocks->contains(block)) {
+ blocks->append(block);
+
+ if (IR::Stmt *terminator = block->terminator()) {
+ if (IR::CJump *cj = terminator->asCJump())
+ block = cj->iffalse;
+ else if (IR::Jump *j = terminator->asJump())
+ block = j->target;
+ }
+ }
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::traceExpression(IR::Expr *e, quint8 r)
+{
+ if (!e) {
+ discard();
+ } else {
+ qSwap(currentReg, r);
+ e->accept(this);
+ qSwap(currentReg, r);
+ }
+}
+
+//
+// expressions
+//
+void QDeclarativeV4CompilerPrivate::visitConst(IR::Const *e)
+{
+ Instr i;
+ switch (e->type) {
+ case IR::BoolType:
+ i.move_reg_bool(currentReg, e->value);
+ gen(i);
+ break;
+
+ case IR::IntType:
+ i.move_reg_int(currentReg, e->value);
+ gen(i);
+ break;
+
+ case IR::RealType:
+ i.move_reg_qreal(currentReg, e->value);
+ gen(i);
+ break;
+
+ default:
+ if (qmlVerboseCompiler())
+ qWarning() << Q_FUNC_INFO << "unexpected type";
+ discard();
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitString(IR::String *e)
+{
+ registerLiteralString(currentReg, e->value);
+}
+
+void QDeclarativeV4CompilerPrivate::visitName(IR::Name *e)
+{
+ if (e->base) {
+ // fetch the object and store it in reg.
+ traceExpression(e->base, currentReg);
+ } else {
+ _subscribeName.clear();
+ }
+
+ if (e->storage == IR::Name::RootStorage) {
+
+ Instr instr;
+ instr.load_root(currentReg);
+ gen(instr);
+
+ if (e->symbol == IR::Name::IdObject) {
+ // The ID is a reference to the root object
+ return;
+ }
+
+ } else if (e->storage == IR::Name::ScopeStorage) {
+
+ Instr instr;
+ instr.load_scope(currentReg);
+ gen(instr);
+
+ _subscribeName << contextName();
+
+ } else if (e->storage == IR::Name::IdStorage) {
+
+ Instr instr;
+ instr.load_id(currentReg, e->index);
+ gen(instr);
+
+ _subscribeName << QLatin1String("$$$ID_") + e->id;
+
+ if (blockNeedsSubscription(_subscribeName)) {
+ Instr sub;
+ sub.subscribeId(currentReg, subscriptionIndex(_subscribeName), instr.load.index);
+ gen(sub);
+ }
+
+ return;
+ } else {
+ // No action needed
+ }
+
+ switch (e->symbol) {
+ case IR::Name::Unbound:
+ case IR::Name::IdObject:
+ case IR::Name::Slot:
+ case IR::Name::Object: {
+ Q_ASSERT(!"Unreachable");
+ discard();
+ } break;
+
+ case IR::Name::AttachType: {
+ _subscribeName << e->id;
+
+ Instr attached;
+ attached.common.type = Instr::LoadAttached;
+ attached.attached.output = currentReg;
+ attached.attached.reg = currentReg;
+ attached.attached.exceptionId = exceptionId(e->line, e->column);
+ Q_ASSERT(e->declarativeType->attachedPropertiesId() != -1);
+ attached.attached.id = e->declarativeType->attachedPropertiesId();
+ gen(attached);
+ } break;
+
+ case IR::Name::Property: {
+ _subscribeName << e->id;
+
+ QMetaProperty prop = e->meta->property(e->index);
+ int fastFetchIndex = fastProperties()->accessorIndexForProperty(e->meta, e->index);
+
+ const int propTy = prop.userType();
+ QDeclarativeRegisterType regType;
+
+ switch (propTy) {
+ case QMetaType::QReal:
+ regType = QRealType;
+ break;
+ case QMetaType::Bool:
+ regType = BoolType;
+ break;
+ case QMetaType::Int:
+ regType = IntType;
+ break;
+ case QMetaType::QString:
+ regType = QStringType;
+ break;
+
+ default:
+ if (propTy == qMetaTypeId<QDeclarativeAnchorLine>()) {
+ regType = PODValueType;
+ } else if (propTy == qMetaTypeId<QSGAnchorLine>()) {
+ regType = PODValueType;
+ } else if (QDeclarativeMetaType::isQObject(propTy)) {
+ regType = QObjectStarType;
+ } else {
+ if (qmlVerboseCompiler())
+ qWarning() << "Discard unsupported property type:" << QMetaType::typeName(propTy);
+ discard(); // Unsupported type
+ return;
+ }
+
+ break;
+ } // switch
+
+ Instr fetch;
+
+ if (fastFetchIndex != -1) {
+ fetch.common.type = Instr::FetchAndSubscribe;
+ fetch.fetchAndSubscribe.reg = currentReg;
+ fetch.fetchAndSubscribe.function = fastFetchIndex;
+ fetch.fetchAndSubscribe.subscription = subscriptionIndex(_subscribeName);
+ fetch.fetchAndSubscribe.exceptionId = exceptionId(e->line, e->column);
+ fetch.fetchAndSubscribe.valueType = regType;
+ } else {
+ if (blockNeedsSubscription(_subscribeName) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
+ Instr sub;
+ sub.subscribe(currentReg, subscriptionIndex(_subscribeName), prop.notifySignalIndex());
+ gen(sub);
+ }
+
+ fetch.common.type = Instr::Fetch;
+ fetch.fetch.reg = currentReg;
+ fetch.fetch.index = e->index;
+ fetch.fetch.exceptionId = exceptionId(e->line, e->column);
+ fetch.fetch.valueType = regType;
+ }
+
+ gen(fetch);
+
+ } break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::visitTemp(IR::Temp *e)
+{
+ if (currentReg != e->index) {
+ Instr i;
+ i.move_reg_reg(currentReg, e->index);
+ gen(i);
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitUnop(IR::Unop *e)
+{
+ Instr i;
+
+ quint8 src = currentReg;
+
+ if (IR::Temp *temp = e->expr->asTemp()) {
+ src = temp->index;
+ } else {
+ traceExpression(e->expr, src);
+ }
+
+ switch (e->op) {
+ case IR::OpInvalid:
+ Q_ASSERT(!"unreachable");
+ break;
+
+ case IR::OpIfTrue:
+ if (src != currentReg) {
+ i.move_reg_reg(currentReg, src);
+ gen(i);
+ } else {
+ // nothing to do
+ }
+ break;
+
+ case IR::OpNot:
+ i.unary_not(currentReg, src);
+ gen(i);
+ break;
+
+ case IR::OpUMinus:
+ if (e->expr->type == IR::RealType) {
+ i.uminus_real(currentReg, src);
+ gen(i);
+ } else if (e->expr->type == IR::IntType) {
+ convertToReal(e->expr, currentReg);
+ i.uminus_real(currentReg, src);
+ gen(i);
+ } else {
+ discard();
+ }
+ break;
+
+ case IR::OpUPlus:
+ if (e->expr->type == IR::RealType) {
+ i.uplus_real(currentReg, src);
+ gen(i);
+ } else if (e->expr->type == IR::IntType) {
+ convertToReal(e->expr, currentReg);
+ i.uplus_real(currentReg, src);
+ gen(i);
+ } else {
+ discard();
+ }
+ break;
+
+ case IR::OpCompl:
+ i.ucompl_real(currentReg, src);
+ gen(i);
+ discard(); // ???
+ break;
+
+ case IR::OpBitAnd:
+ case IR::OpBitOr:
+ case IR::OpBitXor:
+ case IR::OpAdd:
+ case IR::OpSub:
+ case IR::OpMul:
+ case IR::OpDiv:
+ case IR::OpMod:
+ case IR::OpLShift:
+ case IR::OpRShift:
+ case IR::OpURShift:
+ case IR::OpGt:
+ case IR::OpLt:
+ case IR::OpGe:
+ case IR::OpLe:
+ case IR::OpEqual:
+ case IR::OpNotEqual:
+ case IR::OpStrictEqual:
+ case IR::OpStrictNotEqual:
+ case IR::OpAnd:
+ case IR::OpOr:
+ Q_ASSERT(!"unreachable");
+ break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::convertToReal(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::RealType)
+ return;
+
+ Instr conv;
+ conv.unaryop.output = reg;
+ conv.unaryop.src = reg;
+
+ switch (expr->type) {
+ case IR::BoolType:
+ conv.common.type = Instr::ConvertBoolToReal;
+ gen(conv);
+ break;
+
+ case IR::IntType:
+ conv.common.type = Instr::ConvertIntToReal;
+ gen(conv);
+ break;
+
+ case IR::RealType:
+ // nothing to do
+ return;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::convertToInt(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::IntType)
+ return;
+
+ Instr conv;
+ conv.unaryop.output = reg;
+ conv.unaryop.src = reg;
+
+ switch (expr->type) {
+ case IR::BoolType:
+ conv.common.type = Instr::ConvertBoolToInt;
+ gen(conv);
+ break;
+
+ case IR::IntType:
+ // nothing to do
+ return;
+
+ case IR::RealType:
+ conv.common.type = Instr::ConvertRealToInt;
+ gen(conv);
+ break;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+void QDeclarativeV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg)
+{
+ if (expr->type == IR::BoolType)
+ return;
+
+ Instr conv;
+ conv.unaryop.output = reg;
+ conv.unaryop.src = reg;
+
+ switch (expr->type) {
+ case IR::BoolType:
+ // nothing to do
+ break;
+
+ case IR::IntType:
+ conv.common.type = Instr::ConvertIntToBool;
+ gen(conv);
+ break;
+
+ case IR::RealType:
+ conv.common.type = Instr::ConvertRealToBool;
+ gen(conv);
+ return;
+
+ case IR::StringType:
+ conv.common.type = Instr::ConvertStringToBool;
+ gen(conv);
+ return;
+
+ default:
+ discard();
+ break;
+ } // switch
+}
+
+quint8 QDeclarativeV4CompilerPrivate::instructionOpcode(IR::Binop *e)
+{
+ switch (e->op) {
+ case IR::OpInvalid:
+ return Instr::Noop;
+
+ case IR::OpIfTrue:
+ case IR::OpNot:
+ case IR::OpUMinus:
+ case IR::OpUPlus:
+ case IR::OpCompl:
+ return Instr::Noop;
+
+ case IR::OpBitAnd:
+ return Instr::BitAndInt;
+
+ case IR::OpBitOr:
+ return Instr::BitOrInt;
+
+ case IR::OpBitXor:
+ return Instr::BitXorInt;
+
+ case IR::OpAdd:
+ if (e->type == IR::StringType)
+ return Instr::AddString;
+ return Instr::AddReal;
+
+ case IR::OpSub:
+ return Instr::SubReal;
+
+ case IR::OpMul:
+ return Instr::MulReal;
+
+ case IR::OpDiv:
+ return Instr::DivReal;
+
+ case IR::OpMod:
+ return Instr::ModReal;
+
+ case IR::OpLShift:
+ return Instr::LShiftInt;
+
+ case IR::OpRShift:
+ return Instr::RShiftInt;
+
+ case IR::OpURShift:
+ return Instr::URShiftInt;
+
+ case IR::OpGt:
+ if (e->left->type == IR::StringType)
+ return Instr::GtString;
+ return Instr::GtReal;
+
+ case IR::OpLt:
+ if (e->left->type == IR::StringType)
+ return Instr::LtString;
+ return Instr::LtReal;
+
+ case IR::OpGe:
+ if (e->left->type == IR::StringType)
+ return Instr::GeString;
+ return Instr::GeReal;
+
+ case IR::OpLe:
+ if (e->left->type == IR::StringType)
+ return Instr::LeString;
+ return Instr::LeReal;
+
+ case IR::OpEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::EqualString;
+ return Instr::EqualReal;
+
+ case IR::OpNotEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::NotEqualString;
+ return Instr::NotEqualReal;
+
+ case IR::OpStrictEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::StrictEqualString;
+ return Instr::StrictEqualReal;
+
+ case IR::OpStrictNotEqual:
+ if (e->left->type == IR::StringType)
+ return Instr::StrictNotEqualString;
+ return Instr::StrictNotEqualReal;
+
+ case IR::OpAnd:
+ case IR::OpOr:
+ return Instr::Noop;
+
+ } // switch
+
+ return Instr::Noop;
+}
+
+void QDeclarativeV4CompilerPrivate::visitBinop(IR::Binop *e)
+{
+ int left = currentReg;
+ int right = currentReg + 1;
+
+ if (e->left->asTemp() && e->type != IR::StringType) // Not sure if the e->type != String test is needed
+ left = e->left->asTemp()->index;
+ else
+ traceExpression(e->left, left);
+
+ if (IR::Temp *t = e->right->asTemp())
+ right = t->index;
+ else
+ traceExpression(e->right, right);
+
+ if (e->left->type != e->right->type) {
+ if (qmlVerboseCompiler())
+ qWarning().nospace() << "invalid operands to binary operator " << IR::binaryOperator(e->op)
+ << "(`" << IR::binaryOperator(e->left->type)
+ << "' and `"
+ << IR::binaryOperator(e->right->type)
+ << "'";
+ discard();
+ return;
+ }
+
+ switch (e->op) {
+ case IR::OpInvalid:
+ discard();
+ break;
+
+ // unary
+ case IR::OpIfTrue:
+ case IR::OpNot:
+ case IR::OpUMinus:
+ case IR::OpUPlus:
+ case IR::OpCompl:
+ discard();
+ break;
+
+ case IR::OpBitAnd:
+ case IR::OpBitOr:
+ case IR::OpBitXor:
+ case IR::OpLShift:
+ case IR::OpRShift:
+ case IR::OpURShift:
+ convertToInt(e->left, left);
+ convertToInt(e->right, right);
+ break;
+
+ case IR::OpAdd:
+ if (e->type != IR::StringType) {
+ convertToReal(e->left, left);
+ convertToReal(e->right, right);
+ }
+ break;
+
+ case IR::OpSub:
+ case IR::OpMul:
+ case IR::OpDiv:
+ case IR::OpMod:
+ convertToReal(e->left, left);
+ convertToReal(e->right, right);
+ break;
+
+ case IR::OpGt:
+ case IR::OpLt:
+ case IR::OpGe:
+ case IR::OpLe:
+ case IR::OpEqual:
+ case IR::OpNotEqual:
+ case IR::OpStrictEqual:
+ case IR::OpStrictNotEqual:
+ if (e->left->type != IR::StringType) {
+ convertToReal(e->left, left);
+ convertToReal(e->right, right);
+ }
+ break;
+
+ case IR::OpAnd:
+ case IR::OpOr:
+ discard(); // ### unreachable
+ break;
+ } // switch
+
+ const quint8 opcode = instructionOpcode(e);
+ if (opcode != Instr::Noop) {
+ Instr instr;
+ instr.common.type = opcode;
+ instr.binaryop.output = currentReg;
+ instr.binaryop.left = left;
+ instr.binaryop.right = right;
+ gen(instr);
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitCall(IR::Call *call)
+{
+ if (IR::Name *name = call->base->asName()) {
+ if (call->args.size() == 1 && call->args.at(0)->type == IR::RealType) {
+ traceExpression(call->args.at(0), currentReg);
+
+ Instr instr;
+ instr.common.type = Instr::Noop;
+
+ switch (name->builtin) {
+ case IR::NoBuiltinSymbol:
+ break;
+
+ case IR::MathSinBultinFunction:
+ instr.math_sin_real(currentReg);
+ break;
+
+ case IR::MathCosBultinFunction:
+ instr.math_cos_real(currentReg);
+ break;
+
+ case IR::MathRoundBultinFunction:
+ instr.math_round_real(currentReg);
+ break;
+
+ case IR::MathFloorBultinFunction:
+ instr.math_floor_real(currentReg);
+ break;
+
+ case IR::MathPIBuiltinConstant:
+ break;
+ } // switch
+
+ if (instr.common.type != Instr::Noop) {
+ gen(instr);
+ return;
+ }
+ }
+ }
+
+ if (qmlVerboseCompiler())
+ qWarning() << "TODO:" << Q_FUNC_INFO << __LINE__;
+ discard();
+}
+
+
+//
+// statements
+//
+void QDeclarativeV4CompilerPrivate::visitExp(IR::Exp *s)
+{
+ traceExpression(s->expr, currentReg);
+}
+
+void QDeclarativeV4CompilerPrivate::visitMove(IR::Move *s)
+{
+ IR::Temp *target = s->target->asTemp();
+ Q_ASSERT(target != 0);
+
+ quint8 dest = target->index;
+
+ if (target->type != s->source->type) {
+ quint8 src = dest;
+
+ if (IR::Temp *t = s->source->asTemp())
+ src = t->index;
+ else
+ traceExpression(s->source, dest);
+
+ Instr conv;
+ conv.common.type = Instr::Noop;
+ if (target->type == IR::BoolType) {
+ switch (s->source->type) {
+ case IR::IntType: conv.common.type = Instr::ConvertIntToBool; break;
+ case IR::RealType: conv.common.type = Instr::ConvertRealToBool; break;
+ case IR::StringType: conv.common.type = Instr::ConvertStringToBool; break;
+ default: break;
+ } // switch
+ } else if (target->type == IR::IntType) {
+ switch (s->source->type) {
+ case IR::BoolType: conv.common.type = Instr::ConvertBoolToInt; break;
+ case IR::RealType: {
+ if (s->isMoveForReturn)
+ conv.common.type = Instr::MathRoundReal;
+ else
+ conv.common.type = Instr::ConvertRealToInt;
+ break;
+ }
+ case IR::StringType: conv.common.type = Instr::ConvertStringToInt; break;
+ default: break;
+ } // switch
+ } else if (target->type == IR::RealType) {
+ switch (s->source->type) {
+ case IR::BoolType: conv.common.type = Instr::ConvertBoolToReal; break;
+ case IR::IntType: conv.common.type = Instr::ConvertIntToReal; break;
+ case IR::StringType: conv.common.type = Instr::ConvertStringToReal; break;
+ default: break;
+ } // switch
+ } else if (target->type == IR::StringType) {
+ switch (s->source->type) {
+ case IR::BoolType: conv.common.type = Instr::ConvertBoolToString; break;
+ case IR::IntType: conv.common.type = Instr::ConvertIntToString; break;
+ case IR::RealType: conv.common.type = Instr::ConvertRealToString; break;
+ default: break;
+ } // switch
+ }
+ if (conv.common.type != Instr::Noop) {
+ conv.unaryop.output = dest;
+ conv.unaryop.src = src;
+ gen(conv);
+ } else {
+ discard();
+ }
+ } else {
+ traceExpression(s->source, dest);
+ }
+}
+
+void QDeclarativeV4CompilerPrivate::visitJump(IR::Jump *s)
+{
+ patches.append(Patch(s->target, bytecode.size()));
+
+ Instr i;
+ i.branch(0); // ### backpatch
+ gen(i);
+}
+
+void QDeclarativeV4CompilerPrivate::visitCJump(IR::CJump *s)
+{
+ traceExpression(s->cond, currentReg);
+
+ patches.append(Patch(s->iftrue, bytecode.size()));
+
+ Instr i;
+ i.branch_true(currentReg, 0); // ### backpatch
+ gen(i);
+}
+
+void QDeclarativeV4CompilerPrivate::visitRet(IR::Ret *s)
+{
+ Q_ASSERT(s->expr != 0);
+
+ int storeReg = currentReg;
+
+ if (IR::Temp *temp = s->expr->asTemp()) {
+ storeReg = temp->index;
+ } else {
+ traceExpression(s->expr, storeReg);
+ }
+
+ if (qmlBindingsTest) {
+ Instr test;
+ test.common.type = Instr::TestV4Store;
+ test.storetest.reg = storeReg;
+ switch (s->type) {
+ case IR::StringType:
+ test.storetest.regType = QMetaType::QString;
+ break;
+ case IR::UrlType:
+ test.storetest.regType = QMetaType::QUrl;
+ break;
+ case IR::AnchorLineType:
+ test.storetest.regType = qMetaTypeId<QDeclarativeAnchorLine>();
+ break;
+ case IR::SGAnchorLineType:
+ test.storetest.regType = qMetaTypeId<QSGAnchorLine>();
+ break;
+ case IR::ObjectType:
+ test.storetest.regType = QMetaType::QObjectStar;
+ break;
+ case IR::BoolType:
+ test.storetest.regType = QMetaType::Bool;
+ break;
+ case IR::IntType:
+ test.storetest.regType = QMetaType::Int;
+ break;
+ case IR::RealType:
+ test.storetest.regType = QMetaType::QReal;
+ break;
+ default:
+ discard();
+ return;
+ }
+ gen(test);
+ }
+
+ Instr store;
+ store.common.type = Instr::Store;
+ store.store.output = 0;
+ store.store.index = expression->property->index;
+ store.store.reg = storeReg;
+ store.store.exceptionId = exceptionId(s->line, s->column);
+ gen(store);
+}
+
+void QDeclarativeV4Compiler::dump(const QByteArray &programData)
+{
+ const QDeclarativeV4Program *program = (const QDeclarativeV4Program *)programData.constData();
+
+ qWarning() << "Program.bindings:" << program->bindings;
+ qWarning() << "Program.dataLength:" << program->dataLength;
+ qWarning() << "Program.subscriptions:" << program->subscriptions;
+ qWarning() << "Program.indentifiers:" << program->identifiers;
+
+ const int programSize = program->instructionCount;
+ const char *start = program->instructions();
+ const char *code = start;
+ const char *end = code + programSize;
+ while (code < end) {
+ Instr *instr = (Instr *) code;
+ instr->dump(code - start);
+ code += instr->size();
+ }
+}
+
+QDeclarativeFastProperties *QDeclarativeV4Compiler::fastPropertyAccessor()
+{
+ return fastProperties();
+}
+
+/*!
+Clear the state associated with attempting to compile a specific binding.
+This does not clear the global "committed binding" states.
+*/
+void QDeclarativeV4CompilerPrivate::resetInstanceState()
+{
+ registerCleanups.clear();
+ data = committed.data;
+ exceptions = committed.exceptions;
+ usedSubscriptionIds.clear();
+ subscriptionIds = committed.subscriptionIds;
+ registeredStrings = committed.registeredStrings;
+ bytecode.clear();
+ patches.clear();
+ currentReg = 0;
+}
+
+/*!
+Mark the last compile as successful, and add it to the "committed data"
+section.
+
+Returns the index for the committed binding.
+*/
+int QDeclarativeV4CompilerPrivate::commitCompile()
+{
+ int rv = committed.count();
+ committed.offsets << committed.bytecode.count();
+ committed.dependencies << usedSubscriptionIds;
+ committed.bytecode += bytecode.code();
+ committed.data = data;
+ committed.exceptions = exceptions;
+ committed.subscriptionIds = subscriptionIds;
+ committed.registeredStrings = registeredStrings;
+ return rv;
+}
+
+bool QDeclarativeV4CompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
+{
+ resetInstanceState();
+
+ if (expression->property->type == -1)
+ return false;
+
+ AST::SourceLocation location;
+ if (AST::ExpressionNode *astExpression = node->expressionCast()) {
+ location = astExpression->firstSourceLocation();
+ } else if (AST::Statement *astStatement = node->statementCast()) {
+ if (AST::Block *block = AST::cast<AST::Block *>(astStatement))
+ location = block->lbraceToken;
+ else if (AST::IfStatement *ifStmt = AST::cast<AST::IfStatement *>(astStatement))
+ location = ifStmt->ifToken;
+ else
+ return false;
+ } else {
+ return false;
+ }
+
+ IR::Module module;
+ IR::Function *function = 0;
+
+ QDeclarativeV4IRBuilder irBuilder(expression, engine);
+ if (!(function = irBuilder(&module, node)))
+ return false;
+
+ bool discarded = false;
+ qSwap(_discarded, discarded);
+ qSwap(_function, function);
+ trace(location.startLine, location.startColumn);
+ qSwap(_function, function);
+ qSwap(_discarded, discarded);
+
+ if (qmlVerboseCompiler()) {
+ QTextStream qerr(stderr, QIODevice::WriteOnly);
+ if (discarded)
+ qerr << "======== TODO ====== " << endl;
+ else
+ qerr << "==================== " << endl;
+ qerr << "\tline: " << location.startLine
+ << "\tcolumn: " << location.startColumn
+ << endl;
+ foreach (IR::BasicBlock *bb, function->basicBlocks)
+ bb->dump(qerr);
+ qerr << endl;
+ }
+
+ if (discarded || subscriptionIds.count() > 0xFFFF || registeredStrings.count() > 0xFFFF)
+ return false;
+
+ return true;
+}
+
+// Returns a reg
+int QDeclarativeV4CompilerPrivate::registerLiteralString(quint8 reg, const QString &str)
+{
+ // ### string cleanup
+
+ QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
+ int offset = data.count();
+ data += strdata;
+
+ Instr string;
+ string.common.type = Instr::String;
+ string.string_value.reg = reg;
+ string.string_value.offset = offset;
+ string.string_value.length = str.length();
+ gen(string);
+
+ return reg;
+}
+
+// Returns an identifier offset
+int QDeclarativeV4CompilerPrivate::registerString(const QString &string)
+{
+ Q_ASSERT(!string.isEmpty());
+
+ QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
+
+ if (iter == registeredStrings.end()) {
+ quint32 len = string.length();
+ QByteArray lendata((const char *)&len, sizeof(quint32));
+ QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
+ strdata.prepend(lendata);
+ int rv = data.count();
+ data += strdata;
+
+ iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv));
+ }
+
+ Instr reg;
+ reg.common.type = Instr::InitString;
+ reg.initstring.offset = iter->first;
+ reg.initstring.dataIdx = iter->second;
+ gen(reg);
+ return reg.initstring.offset;
+}
+
+/*!
+Returns true if the current expression has not already subscribed to \a sub in currentBlockMask.
+*/
+bool QDeclarativeV4CompilerPrivate::blockNeedsSubscription(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+
+ QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+ if (iter == subscriptionIds.end())
+ return true;
+
+ QHash<int, quint32>::ConstIterator uiter = usedSubscriptionIds.find(*iter);
+ if (uiter == usedSubscriptionIds.end())
+ return true;
+ else
+ return !(*uiter & currentBlockMask);
+}
+
+int QDeclarativeV4CompilerPrivate::subscriptionIndex(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+ QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+ if (iter == subscriptionIds.end())
+ iter = subscriptionIds.insert(str, subscriptionIds.count());
+ if (!(usedSubscriptionIds[*iter] & currentBlockMask)) {
+ usedSubscriptionIds[*iter] |= currentBlockMask;
+ usedSubscriptionIdsChanged = true;
+ }
+ return *iter;
+}
+
+quint32 QDeclarativeV4CompilerPrivate::subscriptionBlockMask(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+
+ QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+ Q_ASSERT(iter != subscriptionIds.end());
+
+ QHash<int, quint32>::ConstIterator uiter = usedSubscriptionIds.find(*iter);
+ Q_ASSERT(uiter != usedSubscriptionIds.end());
+
+ return *uiter;
+}
+
+quint8 QDeclarativeV4CompilerPrivate::exceptionId(quint32 line, quint32 column)
+{
+ quint8 rv = 0xFF;
+ if (exceptions.count() < 0xFF) {
+ rv = (quint8)exceptions.count();
+ quint64 e = line;
+ e <<= 32;
+ e |= column;
+ exceptions.append(e);
+ }
+ return rv;
+}
+
+quint8 QDeclarativeV4CompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
+{
+ quint8 rv = 0xFF;
+ if (n && exceptions.count() < 0xFF) {
+ QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
+ rv = exceptionId(l.startLine, l.startColumn);
+ }
+ return rv;
+}
+
+QDeclarativeV4Compiler::QDeclarativeV4Compiler()
+: d(new QDeclarativeV4CompilerPrivate)
+{
+ qmlBindingsTest |= qmlBindingsTestEnv();
+}
+
+QDeclarativeV4Compiler::~QDeclarativeV4Compiler()
+{
+ delete d; d = 0;
+}
+
+/*
+Returns true if any bindings were compiled.
+*/
+bool QDeclarativeV4Compiler::isValid() const
+{
+ return !d->committed.bytecode.isEmpty();
+}
+
+/*
+-1 on failure, otherwise the binding index to use.
+*/
+int QDeclarativeV4Compiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
+{
+ if (!expression.expression.asAST()) return false;
+
+ if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
+ return -1;
+
+ if (qmlDisableOptimizer())
+ return -1;
+
+ d->expression = &expression;
+ d->engine = engine;
+
+ if (d->compile(expression.expression.asAST())) {
+ return d->commitCompile();
+ } else {
+ return -1;
+ }
+}
+
+QByteArray QDeclarativeV4CompilerPrivate::buildSignalTable() const
+{
+ QHash<int, QList<QPair<int, quint32> > > table;
+
+ for (int ii = 0; ii < committed.count(); ++ii) {
+ const QHash<int, quint32> &deps = committed.dependencies.at(ii);
+ for (QHash<int, quint32>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter)
+ table[iter.key()].append(qMakePair(ii, iter.value()));
+ }
+
+ QVector<quint32> header;
+ QVector<quint32> data;
+ for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
+ header.append(committed.subscriptionIds.count() + data.count());
+ const QList<QPair<int, quint32> > &bindings = table[ii];
+ data.append(bindings.count());
+ for (int jj = 0; jj < bindings.count(); ++jj) {
+ data.append(bindings.at(jj).first);
+ data.append(bindings.at(jj).second);
+ }
+ }
+ header << data;
+
+ return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
+}
+
+QByteArray QDeclarativeV4CompilerPrivate::buildExceptionData() const
+{
+ QByteArray rv;
+ rv.resize(committed.exceptions.count() * sizeof(quint64));
+ ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
+ return rv;
+}
+
+/*
+Returns the compiled program.
+*/
+QByteArray QDeclarativeV4Compiler::program() const
+{
+ QByteArray programData;
+
+ if (isValid()) {
+ QDeclarativeV4Program prog;
+ prog.bindings = d->committed.count();
+
+ Bytecode bc;
+ Instr jump;
+ jump.common.type = Instr::Jump;
+ jump.jump.reg = -1;
+
+ for (int ii = 0; ii < d->committed.count(); ++ii) {
+ jump.jump.count = d->committed.count() - ii - 1;
+ jump.jump.count*= jump.size();
+ jump.jump.count+= d->committed.offsets.at(ii);
+ bc.append(jump);
+ }
+
+
+ QByteArray bytecode = bc.code();
+ bytecode += d->committed.bytecode;
+
+ QByteArray data = d->committed.data;
+ while (data.count() % 4) data.append('\0');
+ prog.signalTableOffset = data.count();
+ data += d->buildSignalTable();
+ while (data.count() % 4) data.append('\0');
+ prog.exceptionDataOffset = data.count();
+ data += d->buildExceptionData();
+
+ prog.dataLength = 4 * ((data.size() + 3) / 4);
+ prog.subscriptions = d->committed.subscriptionIds.count();
+ prog.identifiers = d->committed.registeredStrings.count();
+ prog.instructionCount = bytecode.count();
+ int size = sizeof(QDeclarativeV4Program) + bytecode.count();
+ size += prog.dataLength;
+
+ programData.resize(size);
+ memcpy(programData.data(), &prog, sizeof(QDeclarativeV4Program));
+ if (prog.dataLength)
+ memcpy((char *)((QDeclarativeV4Program *)programData.data())->data(), data.constData(),
+ data.size());
+ memcpy((char *)((QDeclarativeV4Program *)programData.data())->instructions(), bytecode.constData(),
+ bytecode.count());
+ }
+
+ if (bindingsDump()) {
+ qWarning().nospace() << "Subscription slots:";
+
+ for (QHash<QString, int>::ConstIterator iter = d->committed.subscriptionIds.begin();
+ iter != d->committed.subscriptionIds.end();
+ ++iter) {
+ qWarning().nospace() << " " << iter.value() << "\t-> " << iter.key();
+ }
+
+
+ QDeclarativeV4Compiler::dump(programData);
+ }
+
+ return programData;
+}
+
+void QDeclarativeV4Compiler::enableBindingsTest(bool e)
+{
+ if (e)
+ qmlBindingsTest = true;
+ else
+ qmlBindingsTest = qmlBindingsTestEnv();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompiledbindings_p.h b/src/declarative/qml/v4/qdeclarativev4compiler_p.h
index f3d8b4b804..c10691dc87 100644
--- a/src/declarative/qml/qdeclarativecompiledbindings_p.h
+++ b/src/declarative/qml/v4/qdeclarativev4compiler_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QDECLARATIVEBINDINGOPTIMIZATIONS_P_H
-#define QDECLARATIVEBINDINGOPTIMIZATIONS_P_H
+#ifndef QDECLARATIVEV4COMPILER_P_H
+#define QDECLARATIVEV4COMPILER_P_H
//
// W A R N I N G
@@ -60,12 +60,14 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-struct QDeclarativeBindingCompilerPrivate;
-class QDeclarativeBindingCompiler
+class QDeclarativeFastProperties;
+class QDeclarativeTypeNameCache;
+class QDeclarativeV4CompilerPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeV4Compiler
{
public:
- QDeclarativeBindingCompiler();
- ~QDeclarativeBindingCompiler();
+ QDeclarativeV4Compiler();
+ ~QDeclarativeV4Compiler();
// Returns true if bindings were compiled
bool isValid() const;
@@ -77,6 +79,7 @@ public:
QDeclarativeParser::Property *property;
QDeclarativeParser::Variant expression;
QHash<QString, QDeclarativeParser::Object *> ids;
+ QDeclarativeTypeNameCache *importCache;
QDeclarativeImports imports;
};
@@ -87,30 +90,15 @@ public:
QByteArray program() const;
static void dump(const QByteArray &);
+ static QDeclarativeFastProperties *fastPropertyAccessor();
+ static void enableBindingsTest(bool);
private:
- QDeclarativeBindingCompilerPrivate *d;
-};
-
-class QDeclarativeCompiledBindingsPrivate;
-class QDeclarativeCompiledBindings : public QObject, public QDeclarativeAbstractExpression, public QDeclarativeRefCount
-{
-public:
- QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context);
- virtual ~QDeclarativeCompiledBindings();
-
- QDeclarativeAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property);
-
-protected:
- int qt_metacall(QMetaObject::Call, int, void **);
-
-private:
- Q_DISABLE_COPY(QDeclarativeCompiledBindings)
- Q_DECLARE_PRIVATE(QDeclarativeCompiledBindings)
+ QDeclarativeV4CompilerPrivate *d;
};
QT_END_NAMESPACE
QT_END_HEADER
-#endif // QDECLARATIVEBINDINGOPTIMIZATIONS_P_H
+#endif // QDECLARATIVEV4COMPILER_P_H
diff --git a/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h b/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h
new file mode 100644
index 0000000000..1b2a998422
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4compiler_p_p.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4COMPILER_P_P_H
+#define QDECLARATIVEV4COMPILER_P_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 "qdeclarativev4instruction_p.h"
+#include "qdeclarativev4ir_p.h"
+#include <private/qdeclarativeparser_p.h>
+#include <private/qdeclarativeimport_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeV4CompilerPrivate: protected QDeclarativeJS::IR::ExprVisitor,
+ protected QDeclarativeJS::IR::StmtVisitor
+{
+public:
+ QDeclarativeV4CompilerPrivate();
+
+ void resetInstanceState();
+ int commitCompile();
+
+ const QDeclarativeV4Compiler::Expression *expression;
+ QDeclarativeEnginePrivate *engine;
+
+ QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)expression->context, 16); }
+
+ bool compile(QDeclarativeJS::AST::Node *);
+
+ QHash<int, QPair<int, int> > registerCleanups;
+
+ int registerLiteralString(quint8 reg, const QString &);
+ int registerString(const QString &);
+ QHash<QString, QPair<int, int> > registeredStrings;
+ QByteArray data;
+
+ bool blockNeedsSubscription(const QStringList &);
+ int subscriptionIndex(const QStringList &);
+ quint32 subscriptionBlockMask(const QStringList &);
+
+ quint8 exceptionId(quint32 line, quint32 column);
+ quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *);
+ QVector<quint64> exceptions;
+
+ QHash<int, quint32> usedSubscriptionIds;
+
+ QHash<QString, int> subscriptionIds;
+ QDeclarativeJS::Bytecode bytecode;
+
+ // back patching
+ struct Patch {
+ QDeclarativeJS::IR::BasicBlock *block; // the basic block
+ int offset; // the index of the instruction to patch
+ Patch(QDeclarativeJS::IR::BasicBlock *block = 0, int index = -1)
+ : block(block), offset(index) {}
+ };
+ QVector<Patch> patches;
+
+ // Committed binding data
+ struct {
+ QList<int> offsets;
+ QList<QHash<int, quint32> > dependencies;
+
+ //QDeclarativeJS::Bytecode bytecode;
+ QByteArray bytecode;
+ QByteArray data;
+ QHash<QString, int> subscriptionIds;
+ QVector<quint64> exceptions;
+
+ QHash<QString, QPair<int, int> > registeredStrings;
+
+ int count() const { return offsets.count(); }
+ } committed;
+
+ QByteArray buildSignalTable() const;
+ QByteArray buildExceptionData() const;
+
+ void convertToReal(QDeclarativeJS::IR::Expr *expr, int reg);
+ void convertToInt(QDeclarativeJS::IR::Expr *expr, int reg);
+ void convertToBool(QDeclarativeJS::IR::Expr *expr, int reg);
+ quint8 instructionOpcode(QDeclarativeJS::IR::Binop *e);
+
+protected:
+
+ //
+ // tracing
+ //
+ void trace(int line, int column);
+ void trace(QVector<QDeclarativeJS::IR::BasicBlock *> *blocks);
+ void traceExpression(QDeclarativeJS::IR::Expr *e, quint8 r);
+
+ inline void gen(const QDeclarativeJS::Instr &i) { bytecode.append(i); }
+
+ //
+ // expressions
+ //
+ virtual void visitConst(QDeclarativeJS::IR::Const *e);
+ virtual void visitString(QDeclarativeJS::IR::String *e);
+ virtual void visitName(QDeclarativeJS::IR::Name *e);
+ virtual void visitTemp(QDeclarativeJS::IR::Temp *e);
+ virtual void visitUnop(QDeclarativeJS::IR::Unop *e);
+ virtual void visitBinop(QDeclarativeJS::IR::Binop *e);
+ virtual void visitCall(QDeclarativeJS::IR::Call *e);
+
+ //
+ // statements
+ //
+ virtual void visitExp(QDeclarativeJS::IR::Exp *s);
+ virtual void visitMove(QDeclarativeJS::IR::Move *s);
+ virtual void visitJump(QDeclarativeJS::IR::Jump *s);
+ virtual void visitCJump(QDeclarativeJS::IR::CJump *s);
+ virtual void visitRet(QDeclarativeJS::IR::Ret *s);
+
+private:
+ QStringList _subscribeName;
+ QDeclarativeJS::IR::Function *_function;
+ QDeclarativeJS::IR::BasicBlock *_block;
+ void discard() { _discarded = true; }
+ bool _discarded;
+ quint8 currentReg;
+
+ bool usedSubscriptionIdsChanged;
+ quint32 currentBlockMask;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4COMPILER_P_P_H
+
diff --git a/src/declarative/qml/v4/qdeclarativev4instruction.cpp b/src/declarative/qml/v4/qdeclarativev4instruction.cpp
new file mode 100644
index 0000000000..1f24f30c25
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4instruction.cpp
@@ -0,0 +1,559 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4instruction_p.h"
+#include "qdeclarativev4bindings_p.h"
+
+#include <QtCore/qdebug.h>
+#include <private/qdeclarativeglobal_p.h>
+
+// Define this to do a test dump of all the instructions at startup. This is
+// helpful to test that each instruction's Instr::dump() case uses the correct
+// number of tabs etc and otherwise looks correct.
+// #define DEBUG_INSTR_DUMP
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+
+namespace QDeclarativeJS {
+
+#ifdef DEBUG_INSTR_DUMP
+static struct DumpInstrAtStartup {
+ DumpInstrAtStartup() {
+#define DUMP_INSTR_AT_STARTUP(Type, FMT) { Instr i; i.common.type = Instr::Type; i.dump(0); }
+ FOR_EACH_QML_INSTR(DUMP_INSTR_AT_STARTUP);
+ }
+} dump_instr_at_startup;
+#endif
+
+int Instr::size() const
+{
+#define QML_RETURN_INSTR_SIZE(I, FMT) case I: return QML_INSTR_SIZE(I, FMT);
+ switch (common.type) {
+ FOR_EACH_QML_INSTR(QML_RETURN_INSTR_SIZE)
+ }
+#undef QML_RETURN_INSTR_SIZE
+ return 0;
+}
+
+void Instr::dump(int address) const
+{
+ QByteArray leading;
+ if (address != -1) {
+ leading = QByteArray::number(address);
+ leading.prepend(QByteArray(8 - leading.count(), ' '));
+ leading.append("\t");
+ }
+
+#define INSTR_DUMP qWarning().nospace() << leading.constData()
+
+ switch (common.type) {
+ case Instr::Noop:
+ INSTR_DUMP << "\t" << "Noop";
+ break;
+ case Instr::BindingId:
+ INSTR_DUMP << id.line << ":" << id.column << ":";
+ break;
+ case Instr::Subscribe:
+ INSTR_DUMP << "\t" << "Subscribe" << "\t\t" << "Object_Reg(" << subscribeop.reg << ") Notify_Signal(" << subscribeop.index << ") -> Subscribe_Slot(" << subscribeop.offset << ")";
+ break;
+ case Instr::SubscribeId:
+ INSTR_DUMP << "\t" << "SubscribeId" << "\t\t" << "Id_Offset(" << subscribeop.index << ") -> Subscribe_Slot(" << subscribeop.offset << ")";
+ break;
+ case Instr::FetchAndSubscribe:
+ INSTR_DUMP << "\t" << "FetchAndSubscribe" << "\t" << "Object_Reg(" << fetchAndSubscribe.reg << ") Fast_Accessor(" << fetchAndSubscribe.function << ") -> Output_Reg(" << fetchAndSubscribe.reg << ") Subscription_Slot(" << fetchAndSubscribe.subscription << ")";
+ break;
+ case Instr::LoadId:
+ INSTR_DUMP << "\t" << "LoadId" << "\t\t\t" << "Id_Offset(" << load.index << ") -> Output_Reg(" << load.reg << ")";
+ break;
+ case Instr::LoadScope:
+ INSTR_DUMP << "\t" << "LoadScope" << "\t\t" << "-> Output_Reg(" << load.reg << ")";
+ break;
+ case Instr::LoadRoot:
+ INSTR_DUMP << "\t" << "LoadRoot" << "\t\t" << "-> Output_Reg(" << load.reg << ")";
+ break;
+ case Instr::LoadAttached:
+ INSTR_DUMP << "\t" << "LoadAttached" << "\t\t" << "Object_Reg(" << attached.reg << ") Attached_Index(" << attached.id << ") -> Output_Reg(" << attached.output << ")";
+ break;
+ case Instr::UnaryNot:
+ INSTR_DUMP << "\t" << "UnaryNot" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryMinusReal:
+ INSTR_DUMP << "\t" << "UnaryMinusReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryMinusInt:
+ INSTR_DUMP << "\t" << "UnaryMinusInt" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryPlusReal:
+ INSTR_DUMP << "\t" << "UnaryPlusReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::UnaryPlusInt:
+ INSTR_DUMP << "\t" << "UnaryPlusInt" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertBoolToInt:
+ INSTR_DUMP << "\t" << "ConvertBoolToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertBoolToReal:
+ INSTR_DUMP << "\t" << "ConvertBoolToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertBoolToString:
+ INSTR_DUMP << "\t" << "ConvertBoolToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertIntToBool:
+ INSTR_DUMP << "\t" << "ConvertIntToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertIntToReal:
+ INSTR_DUMP << "\t" << "ConvertIntToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertIntToString:
+ INSTR_DUMP << "\t" << "ConvertIntToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertRealToBool:
+ INSTR_DUMP << "\t" << "ConvertRealToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertRealToInt:
+ INSTR_DUMP << "\t" << "ConvertRealToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertRealToString:
+ INSTR_DUMP << "\t" << "ConvertRealToString" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertStringToBool:
+ INSTR_DUMP << "\t" << "ConvertStringToBool" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertStringToInt:
+ INSTR_DUMP << "\t" << "ConvertStringToInt" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::ConvertStringToReal:
+ INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathSinReal:
+ INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathCosReal:
+ INSTR_DUMP << "\t" << "MathCosReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathRoundReal:
+ INSTR_DUMP << "\t" << "MathRoundReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathFloorReal:
+ INSTR_DUMP << "\t" << "MathFloorReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::MathPIReal:
+ INSTR_DUMP << "\t" << "MathPIReal" << "\t\t" << "Input_Reg(" << unaryop.src << ") -> Output_Reg(" << unaryop.output << ")";
+ break;
+ case Instr::Real:
+ INSTR_DUMP << "\t" << "Real" << "\t\t\t" << "Constant(" << real_value.value << ") -> Output_Reg(" << real_value.reg << ")";
+ break;
+ case Instr::Int:
+ INSTR_DUMP << "\t" << "Int" << "\t\t\t" << "Constant(" << int_value.value << ") -> Output_Reg(" << int_value.reg << ")";
+ break;
+ case Instr::Bool:
+ INSTR_DUMP << "\t" << "Bool" << "\t\t\t" << "Constant(" << bool_value.value << ") -> Output_Reg(" << bool_value.reg << ")";
+ break;
+ case Instr::String:
+ INSTR_DUMP << "\t" << "String" << "\t\t\t" << "String_DataIndex(" << string_value.offset << ") String_Length(" << string_value.length << ") -> Output_Register(" << string_value.reg << ")";
+ break;
+ case Instr::EnableV4Test:
+ INSTR_DUMP << "\t" << "EnableV4Test" << "\t\t" << "String_DataIndex(" << string_value.offset << ") String_Length(" << string_value.length << ")";
+ break;
+ case Instr::TestV4Store:
+ INSTR_DUMP << "\t" << "TestV4Store" << "\t\t" << "Input_Reg(" << storetest.reg << ") Reg_Type(" << storetest.regType << ")";
+ break;
+ case Instr::BitAndInt:
+ INSTR_DUMP << "\t" << "BitAndInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::BitOrInt:
+ INSTR_DUMP << "\t" << "BitOrInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::BitXorInt:
+ INSTR_DUMP << "\t" << "BitXorInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::AddReal:
+ INSTR_DUMP << "\t" << "AddReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::AddString:
+ INSTR_DUMP << "\t" << "AddString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::SubReal:
+ INSTR_DUMP << "\t" << "SubReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::MulReal:
+ INSTR_DUMP << "\t" << "MulReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::DivReal:
+ INSTR_DUMP << "\t" << "DivReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::ModReal:
+ INSTR_DUMP << "\t" << "ModReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LShiftInt:
+ INSTR_DUMP << "\t" << "LShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::RShiftInt:
+ INSTR_DUMP << "\t" << "RShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::URShiftInt:
+ INSTR_DUMP << "\t" << "URShiftInt" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GtReal:
+ INSTR_DUMP << "\t" << "GtReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LtReal:
+ INSTR_DUMP << "\t" << "LtReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GeReal:
+ INSTR_DUMP << "\t" << "GeReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LeReal:
+ INSTR_DUMP << "\t" << "LeReal" << "\t\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::EqualReal:
+ INSTR_DUMP << "\t" << "EqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::NotEqualReal:
+ INSTR_DUMP << "\t" << "NotEqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictEqualReal:
+ INSTR_DUMP << "\t" << "StrictEqualReal" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictNotEqualReal:
+ INSTR_DUMP << "\t" << "StrictNotEqualReal" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GtString:
+ INSTR_DUMP << "\t" << "GtString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LtString:
+ INSTR_DUMP << "\t" << "LtString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::GeString:
+ INSTR_DUMP << "\t" << "GeString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::LeString:
+ INSTR_DUMP << "\t" << "LeString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::EqualString:
+ INSTR_DUMP << "\t" << "EqualString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::NotEqualString:
+ INSTR_DUMP << "\t" << "NotEqualString" << "\t\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictEqualString:
+ INSTR_DUMP << "\t" << "StrictEqualString" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::StrictNotEqualString:
+ INSTR_DUMP << "\t" << "StrictNotEqualString" << "\t" << "Input_Reg(" << binaryop.left << ") Input_Reg(" << binaryop.right << ") -> Output_Reg(" << binaryop.output << ")";
+ break;
+ case Instr::NewString:
+ INSTR_DUMP << "\t" << "NewString" << "\t\t" << "Register(" << construct.reg << ")";
+ break;
+ case Instr::NewUrl:
+ INSTR_DUMP << "\t" << "NewUrl" << "\t\t\t" << "Register(" << construct.reg << ")";
+ break;
+ case Instr::CleanupRegister:
+ INSTR_DUMP << "\t" << "CleanupRegister" << "\t\t" << "Register(" << cleanup.reg << ")";
+ break;
+ case Instr::Fetch:
+ INSTR_DUMP << "\t" << "Fetch" << "\t\t\t" << "Object_Reg(" << fetch.reg << ") Property_Index(" << fetch.index << ") -> Output_Reg(" << fetch.reg << ")";
+ break;
+ case Instr::Store:
+ INSTR_DUMP << "\t" << "Store" << "\t\t\t" << "Input_Reg(" << store.reg << ") -> Object_Reg(" << store.output << ") Property_Index(" << store.index << ")";
+ break;
+ case Instr::Copy:
+ INSTR_DUMP << "\t" << "Copy" << "\t\t\t" << "Input_Reg(" << copy.src << ") -> Output_Reg(" << copy.reg << ")";
+ break;
+ case Instr::Jump:
+ if (jump.reg != -1) {
+ INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + jump.count) << ") [if false == Input_Reg(" << jump.reg << ")]";
+ } else {
+ INSTR_DUMP << "\t" << "Jump" << "\t\t\t" << "Address(" << (address + size() + jump.count) << ")";
+ }
+ break;
+ case Instr::BranchFalse:
+ INSTR_DUMP << "\t" << "BranchFalse" << "\t\t" << "Address(" << (address + size() + branchop.offset) << ") [if false == Input_Reg(" << branchop.reg << ")]";
+ break;
+ case Instr::BranchTrue:
+ INSTR_DUMP << "\t" << "BranchTrue" << "\t\t" << "Address(" << (address + size() + branchop.offset) << ") [if true == Input_Reg(" << branchop.reg << ")]";
+ break;
+ case Instr::Branch:
+ INSTR_DUMP << "\t" << "Branch" << "\t\t\t" << "Address(" << (address + size() + branchop.offset) << ")";
+ break;
+ case Instr::InitString:
+ INSTR_DUMP << "\t" << "InitString" << "\t\t" << "String_DataIndex(" << initstring.dataIdx << ") -> String_Slot(" << initstring.offset << ")";
+ break;
+ case Instr::Block:
+ INSTR_DUMP << "\t" << "Block" << "\t\t\t" << "Mask(" << QByteArray::number(blockop.block, 16).constData() << ")";
+ break;
+ default:
+ INSTR_DUMP << "\t" << "Unknown";
+ break;
+ }
+}
+
+void Instr::noop()
+{
+ common.type = Noop;
+}
+
+void Instr::load_root(quint8 reg)
+{
+ common.type = LoadRoot;
+ load.reg = reg;
+ load.index = 0;
+}
+
+void Instr::load_scope(quint8 reg)
+{
+ common.type = LoadScope;
+ load.reg = reg;
+ load.index = 0;
+}
+
+void Instr::load_id(quint8 reg, quint32 idIndex)
+{
+ common.type = LoadId;
+ load.reg = reg;
+ load.index = idIndex;
+}
+
+void Instr::subscribe(qint8 reg, quint16 subscribeSlot, quint32 notifyIndex)
+{
+ common.type = Instr::Subscribe;
+ subscribeop.reg = reg;
+ subscribeop.offset = subscribeSlot;
+ subscribeop.index = notifyIndex;
+}
+
+void Instr::subscribeId(qint8 reg, quint16 subscribeSlot, quint32 idIndex)
+{
+ common.type = Instr::SubscribeId;
+ subscribeop.reg = reg;
+ subscribeop.offset = subscribeSlot;
+ subscribeop.index = idIndex;
+}
+
+void Instr::move_reg_bool(quint8 reg, bool value)
+{
+ common.type = Bool;
+ bool_value.reg = reg;
+ bool_value.value = value;
+}
+
+void Instr::move_reg_int(quint8 reg, int value)
+{
+ common.type = Int;
+ int_value.reg = reg;
+ int_value.value = value;
+}
+
+void Instr::move_reg_qreal(quint8 reg, qreal value)
+{
+ common.type = Real;
+ real_value.reg = reg;
+ real_value.value = value;
+}
+
+void Instr::move_reg_reg(quint8 reg, quint8 src)
+{
+ common.type = Copy;
+ copy.reg = reg;
+ copy.src = src;
+}
+
+void Instr::unary_not(quint8 dest, quint8 src)
+{
+ common.type = UnaryNot;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uminus_real(quint8 dest, quint8 src)
+{
+ common.type = UnaryMinusReal;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uminus_int(quint8 dest, quint8 src)
+{
+ common.type = UnaryMinusInt;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uplus_real(quint8 dest, quint8 src)
+{
+ common.type = UnaryPlusReal;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::uplus_int(quint8 dest, quint8 src)
+{
+ common.type = UnaryPlusInt;
+ unaryop.src = src;
+ unaryop.output = dest;
+}
+
+void Instr::ucompl_real(quint8 dest, quint8 src)
+{
+ Q_UNUSED(dest);
+ Q_UNUSED(src);
+ if (qmlVerboseCompiler())
+ qWarning() << "TODO" << Q_FUNC_INFO;
+}
+
+void Instr::ucompl_int(quint8 dest, quint8 src)
+{
+ Q_UNUSED(dest);
+ Q_UNUSED(src);
+ if (qmlVerboseCompiler())
+ qWarning() << "TODO" << Q_FUNC_INFO;
+}
+
+void Instr::math_sin_real(quint8 reg)
+{
+ common.type = MathSinReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_cos_real(quint8 reg)
+{
+ common.type = MathCosReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_round_real(quint8 reg)
+{
+ common.type = MathRoundReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_floor_real(quint8 reg)
+{
+ common.type = MathFloorReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::math_pi_real(quint8 reg)
+{
+ common.type = MathPIReal;
+ unaryop.src = reg;
+ unaryop.output = reg;
+}
+
+void Instr::branch_true(quint8 reg, qint16 offset)
+{
+ common.type = BranchTrue;
+ branchop.reg = reg;
+ branchop.offset = offset;
+}
+
+void Instr::branch_false(quint8 reg, qint16 offset)
+{
+ common.type = BranchFalse;
+ branchop.reg = reg;
+ branchop.offset = offset;
+}
+
+void Instr::branch(qint16 offset)
+{
+ common.type = Branch;
+ branchop.offset = offset;
+}
+
+void Instr::block(quint32 mask)
+{
+ common.type = Block;
+ blockop.block = mask;
+}
+
+Bytecode::Bytecode()
+{
+#ifdef QML_THREADED_INTERPRETER
+ decodeInstr = QDeclarativeV4Bindings::getDecodeInstrTable();
+#endif
+}
+
+void Bytecode::append(const Instr &instr)
+{
+ const char *it;
+#ifdef QML_THREADED_INTERPRETER
+ Instr i = instr;
+ i.common.code = decodeInstr[i.common.type];
+ it = (const char *) &i;
+#else
+ it = (const char *) &instr;
+#endif
+ d.append(it, instr.size());
+}
+
+void Bytecode::append(const QVector<Instr> &instrs)
+{
+ foreach (const Instr &i, instrs)
+ append(i);
+}
+
+int Bytecode::remove(int offset)
+{
+ const Instr *instr = (const Instr *) (d.begin() + offset);
+ const int instrSize = instr->size();
+ d.remove(offset, instrSize);
+ return instrSize;
+}
+
+const Instr &Bytecode::operator[](int offset) const
+{
+ return *((const Instr *) (d.begin() + offset));
+}
+
+Instr &Bytecode::operator[](int offset)
+{
+ return *((Instr *) (d.begin() + offset));
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4instruction_p.h b/src/declarative/qml/v4/qdeclarativev4instruction_p.h
new file mode 100644
index 0000000000..f6e0bc734a
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4instruction_p.h
@@ -0,0 +1,444 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4INSTRUCTION_P_H
+#define QDECLARATIVEV4INSTRUCTION_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 <QtCore/qglobal.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qvector.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+#define FOR_EACH_QML_INSTR(F) \
+ F(Noop, common) \
+ F(BindingId, id) \
+ F(Subscribe, subscribeop) \
+ F(SubscribeId, subscribeop) \
+ F(FetchAndSubscribe, fetchAndSubscribe) \
+ F(LoadId, load) \
+ F(LoadScope, load) \
+ F(LoadRoot, load) \
+ F(LoadAttached, attached) \
+ F(UnaryNot, unaryop) \
+ F(UnaryMinusReal, unaryop) \
+ F(UnaryMinusInt, unaryop) \
+ F(UnaryPlusReal, unaryop) \
+ F(UnaryPlusInt, unaryop) \
+ F(ConvertBoolToInt, unaryop) \
+ F(ConvertBoolToReal, unaryop) \
+ F(ConvertBoolToString, unaryop) \
+ F(ConvertIntToBool, unaryop) \
+ F(ConvertIntToReal, unaryop) \
+ F(ConvertIntToString, unaryop) \
+ F(ConvertRealToBool, unaryop) \
+ F(ConvertRealToInt, unaryop) \
+ F(ConvertRealToString, unaryop) \
+ F(ConvertStringToBool, unaryop) \
+ F(ConvertStringToInt, unaryop) \
+ F(ConvertStringToReal, unaryop) \
+ F(MathSinReal, unaryop) \
+ F(MathCosReal, unaryop) \
+ F(MathRoundReal, unaryop) \
+ F(MathFloorReal, unaryop) \
+ F(MathPIReal, unaryop) \
+ F(Real, real_value) \
+ F(Int, int_value) \
+ F(Bool, bool_value) \
+ F(String, string_value) \
+ F(EnableV4Test, string_value) \
+ F(TestV4Store, storetest) \
+ F(BitAndInt, binaryop) \
+ F(BitOrInt, binaryop) \
+ F(BitXorInt, binaryop) \
+ F(AddReal, binaryop) \
+ F(AddString, binaryop) \
+ F(SubReal, binaryop) \
+ F(MulReal, binaryop) \
+ F(DivReal, binaryop) \
+ F(ModReal, binaryop) \
+ F(LShiftInt, binaryop) \
+ F(RShiftInt, binaryop) \
+ F(URShiftInt, binaryop) \
+ F(GtReal, binaryop) \
+ F(LtReal, binaryop) \
+ F(GeReal, binaryop) \
+ F(LeReal, binaryop) \
+ F(EqualReal, binaryop) \
+ F(NotEqualReal, binaryop) \
+ F(StrictEqualReal, binaryop) \
+ F(StrictNotEqualReal, binaryop) \
+ F(GtString, binaryop) \
+ F(LtString, binaryop) \
+ F(GeString, binaryop) \
+ F(LeString, binaryop) \
+ F(EqualString, binaryop) \
+ F(NotEqualString, binaryop) \
+ F(StrictEqualString, binaryop) \
+ F(StrictNotEqualString, binaryop) \
+ F(NewString, construct) \
+ F(NewUrl, construct) \
+ F(CleanupRegister, cleanup) \
+ F(Copy, copy) \
+ F(Fetch, fetch) \
+ F(Store, store) \
+ F(Jump, jump) \
+ F(BranchTrue, branchop) \
+ F(BranchFalse, branchop) \
+ F(Branch, branchop) \
+ F(Block, blockop) \
+ /* Speculative property resolution */ \
+ F(InitString, initstring)
+
+#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
+# define QML_THREADED_INTERPRETER
+#endif
+
+#ifdef Q_ALIGNOF
+# define QML_INSTR_ALIGN_MASK (Q_ALIGNOF(Instr) - 1)
+#else
+# define QML_INSTR_ALIGN_MASK (sizeof(void *) - 1)
+#endif
+
+#define QML_INSTR_ENUM(I, FMT) I,
+#define QML_INSTR_ADDR(I, FMT) &&op_##I,
+#define QML_INSTR_SIZE(I, FMT) ((sizeof(Instr::instr_##FMT) + QML_INSTR_ALIGN_MASK) & ~QML_INSTR_ALIGN_MASK)
+
+#ifdef QML_THREADED_INTERPRETER
+# define QML_BEGIN_INSTR(I,FMT) op_##I:
+# define QML_END_INSTR(I,FMT) code += QML_INSTR_SIZE(I, FMT); instr = (const Instr *) code; goto *instr->common.code;
+# define QML_INSTR_HEADER void *code;
+#else
+# define QML_BEGIN_INSTR(I,FMT) case Instr::I:
+# define QML_END_INSTR(I,FMT) code += QML_INSTR_SIZE(I, FMT); instr = (const Instr *) code; break;
+# define QML_INSTR_HEADER
+#endif
+
+namespace QDeclarativeJS {
+
+union Instr {
+ int size() const;
+ void dump(int = -1) const;
+ void noop();
+ void load_root(quint8 reg);
+ void load_scope(quint8 reg);
+ void load_id(quint8 reg, quint32 idIndex);
+ void subscribe(qint8 reg, quint16 offset, quint32 index);
+ void subscribeId(qint8 reg, quint16 offset, quint32 index);
+ void move_reg_bool(quint8 reg, bool value);
+ void move_reg_int(quint8 reg, int value);
+ void move_reg_qreal(quint8 reg, qreal value);
+ void move_reg_reg(quint8 reg, quint8 src);
+
+ void unary_not(quint8 dest, quint8 src);
+ void uminus_real(quint8 dest, quint8 src);
+ void uminus_int(quint8 dest, quint8 src);
+ void uplus_real(quint8 dest, quint8 src);
+ void uplus_int(quint8 dest, quint8 src);
+ void ucompl_real(quint8 dest, quint8 src);
+ void ucompl_int(quint8 dest, quint8 src);
+
+ void math_sin_real(quint8 reg);
+ void math_cos_real(quint8 reg);
+ void math_round_real(quint8 reg);
+ void math_floor_real(quint8 reg);
+ void math_pi_real(quint8 reg);
+ void branch_true(quint8 reg, qint16 offset);
+ void branch_false(quint8 reg, qint16 offset);
+ void branch(qint16 offset);
+ void block(quint32 mask);
+
+ enum {
+ FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
+ };
+
+ struct instr_common {
+ QML_INSTR_HEADER
+ quint8 type;
+ };
+
+ struct instr_id {
+ QML_INSTR_HEADER
+ quint8 type;
+ quint16 column;
+ quint32 line;
+ };
+
+ struct instr_init {
+ QML_INSTR_HEADER
+ quint8 type;
+ quint16 subscriptions;
+ quint16 identifiers;
+ };
+
+ struct instr_subscribeop {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint16 offset;
+ quint32 index;
+ };
+
+ struct instr_load {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint32 index;
+ };
+
+ struct instr_attached {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 reg;
+ quint8 exceptionId;
+ quint32 id;
+ };
+
+ struct instr_store {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 reg;
+ quint8 exceptionId;
+ quint32 index;
+ };
+
+ struct instr_storetest {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qint32 regType;
+ };
+
+ struct instr_fetchAndSubscribe {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint8 exceptionId;
+ quint8 valueType;
+ quint16 subscription;
+ quint16 function;
+ };
+
+ struct instr_fetch{
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint8 exceptionId;
+ quint8 valueType;
+ quint32 index;
+ };
+
+ struct instr_copy {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qint8 src;
+ };
+
+ struct instr_construct {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ };
+
+ struct instr_real_value {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qreal value; // XXX Makes the instruction 12 bytes
+ };
+
+ struct instr_int_value {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ int value;
+ };
+
+ struct instr_bool_value {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ bool value;
+ };
+
+ struct instr_string_value {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint16 length;
+ quint32 offset;
+ };
+
+ struct instr_binaryop {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 left;
+ qint8 right;
+ };
+
+ struct instr_unaryop {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 output;
+ qint8 src;
+ };
+
+ struct instr_jump {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ quint32 count;
+ };
+
+ struct instr_find {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ qint8 src;
+ quint8 exceptionId;
+ quint16 name;
+ quint16 subscribeIndex;
+ };
+
+ struct instr_cleanup {
+ QML_INSTR_HEADER
+ quint8 type;
+ qint8 reg;
+ };
+
+ struct instr_initstring {
+ QML_INSTR_HEADER
+ quint8 type;
+ quint16 offset;
+ quint32 dataIdx;
+ };
+
+ struct instr_branchop {
+ QML_INSTR_HEADER
+ quint8 type;
+ quint8 reg;
+ qint16 offset;
+ };
+
+ struct instr_blockop {
+ QML_INSTR_HEADER
+ quint8 type;
+ quint32 block;
+ };
+
+ instr_common common;
+ instr_id id;
+ instr_init init;
+ instr_subscribeop subscribeop;
+ instr_load load;
+ instr_attached attached;
+ instr_store store;
+ instr_storetest storetest;
+ instr_fetchAndSubscribe fetchAndSubscribe;
+ instr_fetch fetch;
+ instr_copy copy;
+ instr_construct construct;
+ instr_real_value real_value;
+ instr_int_value int_value;
+ instr_bool_value bool_value;
+ instr_string_value string_value;
+ instr_binaryop binaryop;
+ instr_unaryop unaryop;
+ instr_jump jump;
+ instr_find find;
+ instr_cleanup cleanup;
+ instr_initstring initstring;
+ instr_branchop branchop;
+ instr_blockop blockop;
+};
+
+class Bytecode
+{
+ Q_DISABLE_COPY(Bytecode)
+
+public:
+ Bytecode();
+
+ QByteArray code() const { return d; }
+ const char *constData() const { return d.constData(); }
+ int size() const { return d.size(); }
+ int count() const { return d.count(); }
+ void clear() { d.clear(); }
+ bool isEmpty() const { return d.isEmpty(); }
+ void append(const Instr &instr);
+ void append(const QVector<Instr> &instrs);
+ int remove(int index);
+
+ const Instr &operator[](int offset) const;
+ Instr &operator[](int offset);
+
+private:
+ QByteArray d;
+#ifdef QML_THREADED_INTERPRETER
+ void **decodeInstr;
+#endif
+};
+
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4INSTRUCTION_P_H
+
diff --git a/src/declarative/qml/v4/qdeclarativev4ir.cpp b/src/declarative/qml/v4/qdeclarativev4ir.cpp
new file mode 100644
index 0000000000..7876e6ccea
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4ir.cpp
@@ -0,0 +1,832 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4ir_p.h"
+
+#include <QtCore/qtextstream.h>
+#include <QtCore/qdebug.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+namespace IR {
+
+inline const char *typeName(Type t)
+{
+ switch (t) {
+ case InvalidType: return "invalid";
+ case UndefinedType: return "undefined";
+ case NullType: return "null";
+ case VoidType: return "void";
+ case StringType: return "string";
+ case UrlType: return "url";
+ case AnchorLineType: return "AnchorLine";
+ case SGAnchorLineType: return "SGAnchorLine";
+ case AttachType: return "AttachType";
+ case ObjectType: return "object";
+ case BoolType: return "bool";
+ case IntType: return "int";
+ case RealType: return "qreal";
+ case RealNaNType: return "NaN";
+ default: return "invalid";
+ }
+}
+
+IR::Type maxType(IR::Type left, IR::Type right)
+{
+ if (left == right)
+ return left;
+ else if (left >= IR::FirstNumberType && right >= IR::FirstNumberType)
+ return qMax(left, right);
+ else if ((left >= IR::FirstNumberType && right == IR::StringType) ||
+ (right >= IR::FirstNumberType && left == IR::StringType))
+ return IR::StringType;
+ else
+ return IR::InvalidType;
+}
+
+
+const char *opname(AluOp op)
+{
+ switch (op) {
+ case OpInvalid: return "?";
+
+ case OpIfTrue: return "(bool)";
+ case OpNot: return "!";
+ case OpUMinus: return "-";
+ case OpUPlus: return "+";
+ case OpCompl: return "~";
+
+ case OpBitAnd: return "&";
+ case OpBitOr: return "|";
+ case OpBitXor: return "^";
+
+ case OpAdd: return "+";
+ case OpSub: return "-";
+ case OpMul: return "*";
+ case OpDiv: return "/";
+ case OpMod: return "%";
+
+ case OpLShift: return "<<";
+ case OpRShift: return ">>";
+ case OpURShift: return ">>>";
+
+ case OpGt: return ">";
+ case OpLt: return "<";
+ case OpGe: return ">=";
+ case OpLe: return "<=";
+ case OpEqual: return "==";
+ case OpNotEqual: return "!=";
+ case OpStrictEqual: return "===";
+ case OpStrictNotEqual: return "!==";
+
+ case OpAnd: return "&&";
+ case OpOr: return "||";
+
+ default: return "?";
+
+ } // switch
+}
+
+AluOp binaryOperator(int op)
+{
+ switch (static_cast<QSOperator::Op>(op)) {
+ case QSOperator::Add: return OpAdd;
+ case QSOperator::And: return OpAnd;
+ case QSOperator::BitAnd: return OpBitAnd;
+ case QSOperator::BitOr: return OpBitOr;
+ case QSOperator::BitXor: return OpBitXor;
+ case QSOperator::Div: return OpDiv;
+ case QSOperator::Equal: return OpEqual;
+ case QSOperator::Ge: return OpGe;
+ case QSOperator::Gt: return OpGt;
+ case QSOperator::Le: return OpLe;
+ case QSOperator::LShift: return OpLShift;
+ case QSOperator::Lt: return OpLt;
+ case QSOperator::Mod: return OpMod;
+ case QSOperator::Mul: return OpMul;
+ case QSOperator::NotEqual: return OpNotEqual;
+ case QSOperator::Or: return OpOr;
+ case QSOperator::RShift: return OpRShift;
+ case QSOperator::StrictEqual: return OpStrictEqual;
+ case QSOperator::StrictNotEqual: return OpStrictNotEqual;
+ case QSOperator::Sub: return OpSub;
+ case QSOperator::URShift: return OpURShift;
+ default: return OpInvalid;
+ }
+}
+
+void Const::dump(QTextStream &out)
+{
+ out << value;
+}
+
+void String::dump(QTextStream &out)
+{
+ out << '"' << escape(value) << '"';
+}
+
+QString String::escape(const QString &s)
+{
+ QString r;
+ foreach (const QChar &ch, s) {
+ if (ch == QLatin1Char('\n'))
+ r += QLatin1String("\\n");
+ else if (ch == QLatin1Char('\r'))
+ r += QLatin1String("\\r");
+ else if (ch == QLatin1Char('\\'))
+ r += QLatin1String("\\\\");
+ else if (ch == QLatin1Char('"'))
+ r += QLatin1String("\\\"");
+ else if (ch == QLatin1Char('\''))
+ r += QLatin1String("\\'");
+ else
+ r += ch;
+ }
+ return r;
+}
+
+Name::Name(Name *base, Type type, const QString &id, Symbol symbol, quint32 line, quint32 column)
+: Expr(type)
+ , base(base)
+ , id(id)
+ , symbol(symbol)
+ , ptr(0)
+ , index(-1)
+ , storage(MemberStorage)
+ , builtin(NoBuiltinSymbol)
+ , line(line)
+ , column(column)
+{
+ if (id.length() == 8 && id == QLatin1String("Math.sin")) {
+ builtin = MathSinBultinFunction;
+ } else if (id.length() == 8 && id == QLatin1String("Math.cos")) {
+ builtin = MathCosBultinFunction;
+ } else if (id.length() == 10 && id == QLatin1String("Math.round")) {
+ builtin = MathRoundBultinFunction;
+ } else if (id.length() == 10 && id == QLatin1String("Math.floor)")) {
+ builtin = MathFloorBultinFunction;
+ } else if (id.length() == 7 && id == QLatin1String("Math.PI")) {
+ builtin = MathPIBuiltinConstant;
+ type = RealType;
+ }
+}
+
+void Name::dump(QTextStream &out)
+{
+ if (base) {
+ base->dump(out);
+ out << '.';
+ }
+
+ out << id;
+}
+
+void Temp::dump(QTextStream &out)
+{
+ out << 't' << index;
+}
+
+void Unop::dump(QTextStream &out)
+{
+ out << opname(op);
+ expr->dump(out);
+}
+
+Type Unop::typeForOp(AluOp op, Expr *expr)
+{
+ switch (op) {
+ case OpIfTrue: return BoolType;
+ case OpNot: return BoolType;
+
+ case OpUMinus:
+ case OpUPlus:
+ case OpCompl:
+ return maxType(expr->type, RealType);
+
+ default:
+ break;
+ }
+
+ return InvalidType;
+}
+
+void Binop::dump(QTextStream &out)
+{
+ left->dump(out);
+ out << ' ' << opname(op) << ' ';
+ right->dump(out);
+}
+
+Type Binop::typeForOp(AluOp op, Expr *left, Expr *right)
+{
+ if (! (left && right))
+ return InvalidType;
+
+ switch (op) {
+ case OpInvalid:
+ return InvalidType;
+
+ // unary operators
+ case OpIfTrue:
+ case OpNot:
+ case OpUMinus:
+ case OpUPlus:
+ case OpCompl:
+ return InvalidType;
+
+ // bit fields
+ case OpBitAnd:
+ case OpBitOr:
+ case OpBitXor:
+ return IntType;
+
+ case OpAdd:
+ if (left->type == StringType)
+ return StringType;
+ return RealType;
+
+ case OpSub:
+ case OpMul:
+ case OpDiv:
+ case OpMod:
+ return RealType;
+
+ case OpLShift:
+ case OpRShift:
+ case OpURShift:
+ return IntType;
+
+ case OpAnd:
+ case OpOr:
+ return BoolType;
+
+ case OpGt:
+ case OpLt:
+ case OpGe:
+ case OpLe:
+ case OpEqual:
+ case OpNotEqual:
+ case OpStrictEqual:
+ case OpStrictNotEqual:
+ return BoolType;
+ } // switch
+
+ return InvalidType;
+}
+
+void Call::dump(QTextStream &out)
+{
+ base->dump(out);
+ out << '(';
+ for (int i = 0; i < args.size(); ++i) {
+ if (i)
+ out << ", ";
+ args.at(i)->dump(out);
+ }
+ out << ')';
+}
+
+Type Call::typeForFunction(Expr *base)
+{
+ if (! base)
+ return InvalidType;
+
+ if (Name *name = base->asName()) {
+ switch (name->builtin) {
+ case MathSinBultinFunction:
+ case MathCosBultinFunction:
+ return RealType;
+
+ case MathRoundBultinFunction:
+ case MathFloorBultinFunction:
+ return IntType;
+
+ case NoBuiltinSymbol:
+ case MathPIBuiltinConstant:
+ break;
+ }
+ } // switch
+
+ return InvalidType;
+}
+
+void Exp::dump(QTextStream &out, Mode)
+{
+ out << "(void) ";
+ expr->dump(out);
+ out << ';';
+}
+
+void Move::dump(QTextStream &out, Mode)
+{
+ target->dump(out);
+ out << " = ";
+ if (source->type != target->type)
+ out << typeName(source->type) << "_to_" << typeName(target->type) << '(';
+ source->dump(out);
+ if (source->type != target->type)
+ out << ')';
+ out << ';';
+}
+
+void Jump::dump(QTextStream &out, Mode mode)
+{
+ Q_UNUSED(mode);
+ out << "goto " << 'L' << target << ';';
+}
+
+void CJump::dump(QTextStream &out, Mode mode)
+{
+ Q_UNUSED(mode);
+ out << "if (";
+ cond->dump(out);
+ out << ") goto " << 'L' << iftrue << "; else goto " << 'L' << iffalse << ';';
+}
+
+void Ret::dump(QTextStream &out, Mode)
+{
+ out << "return";
+ if (expr) {
+ out << ' ';
+ expr->dump(out);
+ }
+ out << ';';
+}
+
+Function::~Function()
+{
+ qDeleteAll(basicBlocks);
+ qDeleteAll(temps);
+}
+
+BasicBlock *Function::newBasicBlock()
+{
+ const int index = basicBlocks.size();
+ return i(new BasicBlock(this, index));
+}
+
+void Function::dump(QTextStream &out)
+{
+ QString fname;
+ if (name)
+ fname = name->asString();
+ else
+ fname = QLatin1String("$anonymous");
+ out << "function " << fname << "() {" << endl;
+ foreach (BasicBlock *bb, basicBlocks) {
+ bb->dump(out);
+ }
+ out << '}' << endl;
+}
+
+Temp *BasicBlock::TEMP(Type type, int index)
+{
+ return function->e(new Temp(type, index));
+}
+
+Temp *BasicBlock::TEMP(Type type)
+{
+ return TEMP(type, function->tempCount++);
+}
+
+Expr *BasicBlock::CONST(double value)
+{
+ return CONST(IR::RealType, value);
+}
+
+Expr *BasicBlock::CONST(Type type, double value)
+{
+ return function->e(new Const(type, value));
+}
+
+Expr *BasicBlock::STRING(const QString &value)
+{
+ return function->e(new String(value));
+}
+
+Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
+{
+ return NAME(0, id, line, column);
+}
+
+Name *BasicBlock::NAME(Name *base, const QString &id, quint32 line, quint32 column)
+{
+ return function->e(new Name(base, InvalidType, id, Name::Unbound, line, column));
+}
+
+Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = SYMBOL(/*base = */ 0, type, id, meta, index, line, column);
+ name->storage = storage;
+ return name;
+}
+
+Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = new Name(base, type, id, Name::Property, line, column);
+ name->meta = meta;
+ name->index = index;
+ name->storage = storage;
+ return function->e(name);
+}
+
+Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index,
+ quint32 line, quint32 column)
+{
+ Name *name = new Name(base, type, id, Name::Property, line, column);
+ name->meta = meta;
+ name->index = index;
+ return function->e(name);
+}
+
+Name *BasicBlock::ID_OBJECT(const QString &id, const QDeclarativeParser::Object *object, quint32 line, quint32 column)
+{
+ Name *name = new Name(/*base = */ 0, IR::ObjectType, id, Name::IdObject, line, column);
+ name->idObject = object;
+ name->index = object->idIndex;
+ name->storage = Name::IdStorage;
+ return function->e(name);
+}
+
+Name *BasicBlock::ATTACH_TYPE(const QString &id, const QDeclarativeType *attachType, Name::Storage storage,
+ quint32 line, quint32 column)
+{
+ Name *name = new Name(/*base = */ 0, IR::AttachType, id, Name::AttachType, line, column);
+ name->declarativeType = attachType;
+ name->storage = storage;
+ return function->e(name);
+}
+
+
+Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
+{
+ return function->e(new Unop(op, expr));
+}
+
+Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
+{
+ if (left && right) {
+ if (Const *c1 = left->asConst()) {
+ if (Const *c2 = right->asConst()) {
+ switch (op) {
+ case OpAdd: return CONST(c1->value + c2->value);
+ case OpAnd: return CONST(c1->value ? c2->value : 0);
+ case OpBitAnd: return CONST(int(c1->value) & int(c2->value));
+ case OpBitOr: return CONST(int(c1->value) | int(c2->value));
+ case OpBitXor: return CONST(int(c1->value) ^ int(c2->value));
+ case OpDiv: return CONST(c1->value / c2->value);
+ case OpEqual: return CONST(c1->value == c2->value);
+ case OpGe: return CONST(c1->value >= c2->value);
+ case OpGt: return CONST(c1->value > c2->value);
+ case OpLe: return CONST(c1->value <= c2->value);
+ case OpLShift: return CONST(int(c1->value) << int(c2->value));
+ case OpLt: return CONST(c1->value < c2->value);
+ case OpMod: return CONST(::fmod(c1->value, c2->value));
+ case OpMul: return CONST(c1->value * c2->value);
+ case OpNotEqual: return CONST(c1->value != c2->value);
+ case OpOr: return CONST(c1->value ? c1->value : c2->value);
+ case OpRShift: return CONST(int(c1->value) >> int(c2->value));
+ case OpStrictEqual: return CONST(c1->value == c2->value);
+ case OpStrictNotEqual: return CONST(c1->value != c2->value);
+ case OpSub: return CONST(c1->value - c2->value);
+ case OpURShift: return CONST(unsigned(c1->value) >> int(c2->value));
+
+ case OpIfTrue: // unary ops
+ case OpNot:
+ case OpUMinus:
+ case OpUPlus:
+ case OpCompl:
+ case OpInvalid:
+ break;
+ }
+ }
+ }
+ }
+
+ return function->e(new Binop(op, left, right));
+}
+
+Expr *BasicBlock::CALL(Expr *base, const QVector<Expr *> &args)
+{
+ return function->e(new Call(base, args));
+}
+
+Stmt *BasicBlock::EXP(Expr *expr)
+{
+ return i(new Exp(expr));
+}
+
+Stmt *BasicBlock::MOVE(Expr *target, Expr *source, bool isMoveForReturn)
+{
+ return i(new Move(target, source, isMoveForReturn));
+}
+
+Stmt *BasicBlock::JUMP(BasicBlock *target)
+{
+ if (isTerminated())
+ return 0;
+ else
+ return i(new Jump(target));
+}
+
+Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+{
+ if (isTerminated())
+ return 0;
+ return i(new CJump(cond, iftrue, iffalse));
+}
+
+Stmt *BasicBlock::RET(Expr *expr, Type type, quint32 line, quint32 column)
+{
+ if (isTerminated())
+ return 0;
+ else
+ return i(new Ret(expr, type, line, column));
+}
+
+void BasicBlock::dump(QTextStream &out)
+{
+ out << 'L' << this << ':' << endl;
+ foreach (Stmt *s, statements) {
+ out << '\t';
+ s->dump(out);
+ out << endl;
+ }
+}
+
+void Module::dump(QTextStream &out)
+{
+ foreach (Function *fun, functions) {
+ fun->dump(out);
+ out << endl;
+ }
+}
+
+#ifdef DEBUG_IR_STRUCTURE
+
+static const char *symbolname(Name::Symbol s)
+{
+ switch (s) {
+ case Name::Unbound:
+ return "Unbound";
+ case Name::IdObject:
+ return "IdObject";
+ case Name::AttachType:
+ return "AttachType";
+ case Name::Object:
+ return "Object";
+ case Name::Property:
+ return "Property";
+ case Name::Slot:
+ return "Slot";
+ default:
+ Q_ASSERT(!"Unreachable");
+ return "Unknown";
+ }
+}
+
+static const char *storagename(Name::Storage s)
+{
+ switch (s) {
+ case Name::MemberStorage:
+ return "MemberStorage";
+ case Name::IdStorage:
+ return "IdStorage";
+ case Name::RootStorage:
+ return "RootStorage";
+ case Name::ScopeStorage:
+ return "ScopeStorage";
+ default:
+ Q_ASSERT(!"Unreachable");
+ return "UnknownStorage";
+ }
+}
+
+IRDump::IRDump()
+: indentSize(0)
+{
+}
+
+void IRDump::inc()
+{
+ indentSize++;
+ indentData = QByteArray(indentSize * 4, ' ');
+}
+
+void IRDump::dec()
+{
+ indentSize--;
+ indentData = QByteArray(indentSize * 4, ' ');
+}
+
+void IRDump::dec();
+
+void IRDump::expression(QDeclarativeJS::IR::Expr *e)
+{
+ inc();
+
+ e->accept(this);
+
+ dec();
+}
+
+void IRDump::basicblock(QDeclarativeJS::IR::BasicBlock *b)
+{
+ inc();
+
+ qWarning().nospace() << indent() << "BasicBlock " << b << " {";
+ for (int ii = 0; ii < b->statements.count(); ++ii) {
+ statement(b->statements.at(ii));
+ if (ii != (b->statements.count() - 1))
+ qWarning();
+ }
+ qWarning().nospace() << indent() << "}";
+
+ dec();
+}
+
+void IRDump::statement(QDeclarativeJS::IR::Stmt *s)
+{
+ inc();
+
+ s->accept(this);
+
+ dec();
+}
+
+void IRDump::function(QDeclarativeJS::IR::Function *f)
+{
+ inc();
+
+ qWarning().nospace() << indent() << "Function {";
+ for (int ii = 0; ii < f->basicBlocks.count(); ++ii) {
+ basicblock(f->basicBlocks.at(ii));
+ }
+ qWarning().nospace() << indent() << "}";
+
+ dec();
+}
+
+const char *IRDump::indent()
+{
+ return indentData.constData();
+}
+
+void IRDump::visitConst(QDeclarativeJS::IR::Const *e)
+{
+ qWarning().nospace() << indent() << "Const:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
+}
+
+void IRDump::visitString(QDeclarativeJS::IR::String *e)
+{
+ qWarning().nospace() << indent() << "String:Expr { type: " << typeName(e->type) << ", value: " << e->value << "}";
+}
+
+static void namedumprecur(QDeclarativeJS::IR::Name *e, const char *indent)
+{
+ if (e->base) namedumprecur(e->base, indent);
+ qWarning().nospace() << indent << " { type: " << typeName(e->type) << ", symbol: " << symbolname(e->symbol) << ", storage: " << storagename(e->storage) << ", id: " << e->id << "}";
+}
+
+void IRDump::visitName(QDeclarativeJS::IR::Name *e)
+{
+ qWarning().nospace() << indent() << "Name:Expr {";
+ namedumprecur(e, indent());
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitTemp(QDeclarativeJS::IR::Temp *e)
+{
+ qWarning().nospace() << indent() << "Temp:Expr { type: " << typeName(e->type) << ", index: " << e->index << " }";
+}
+
+void IRDump::visitUnop(QDeclarativeJS::IR::Unop *e)
+{
+ qWarning().nospace() << indent() << "Unop:Expr { ";
+ qWarning().nospace() << indent() << " type: " << typeName(e->type) << ", op: " << opname(e->op);
+ qWarning().nospace() << indent() << " expr: {";
+ expression(e->expr);
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitBinop(QDeclarativeJS::IR::Binop *e)
+{
+ qWarning().nospace() << indent() << "Binop:Expr { ";
+ qWarning().nospace() << indent() << " type: " << typeName(e->type) << ", op: " << opname(e->op);
+ qWarning().nospace() << indent() << " left: {";
+ inc();
+ expression(e->left);
+ dec();
+ qWarning().nospace() << indent() << " },";
+ qWarning().nospace() << indent() << " right: {";
+ inc();
+ expression(e->right);
+ dec();
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitCall(QDeclarativeJS::IR::Call *e)
+{
+ Q_UNUSED(e);
+ qWarning().nospace() << indent() << "Exp::Call { }";
+}
+
+void IRDump::visitExp(QDeclarativeJS::IR::Exp *s)
+{
+ qWarning().nospace() << indent() << "Exp:Stmt {";
+ expression(s->expr);
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitMove(QDeclarativeJS::IR::Move *s)
+{
+ qWarning().nospace() << indent() << "Move:Stmt {";
+ qWarning().nospace() << indent() << " isMoveForReturn: " << s->isMoveForReturn;
+ qWarning().nospace() << indent() << " target: {";
+ inc();
+ expression(s->target);
+ dec();
+ qWarning().nospace() << indent() << " },";
+ qWarning().nospace() << indent() << " source: {";
+ inc();
+ expression(s->source);
+ dec();
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitJump(QDeclarativeJS::IR::Jump *s)
+{
+ qWarning().nospace() << indent() << "Jump:Stmt { BasicBlock(" << s->target << ") }";
+}
+
+void IRDump::visitCJump(QDeclarativeJS::IR::CJump *s)
+{
+ qWarning().nospace() << indent() << "CJump:Stmt {";
+ qWarning().nospace() << indent() << " cond: {";
+ inc();
+ expression(s->cond);
+ dec();
+ qWarning().nospace() << indent() << " }";
+ qWarning().nospace() << indent() << " iftrue: BasicBlock(" << s->iftrue << ")";
+ qWarning().nospace() << indent() << " iffalse: BasicBlock(" << s->iffalse << ")";
+ qWarning().nospace() << indent() << "}";
+}
+
+void IRDump::visitRet(QDeclarativeJS::IR::Ret *s)
+{
+ qWarning().nospace() << indent() << "Ret:Stmt {";
+ qWarning().nospace() << indent() << " type: " << typeName(s->type);
+ expression(s->expr);
+ qWarning().nospace() << indent() << "}";
+}
+#endif
+
+} // end of namespace IR
+} // end of namespace QDeclarativeJS
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4ir_p.h b/src/declarative/qml/v4/qdeclarativev4ir_p.h
new file mode 100644
index 0000000000..93815e9154
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4ir_p.h
@@ -0,0 +1,546 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4IR_P_H
+#define QDECLARATIVEV4IR_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/qdeclarativejsast_p.h>
+#include <private/qdeclarativejsengine_p.h>
+#include <private/qdeclarativeparser_p.h>
+#include <private/qdeclarativeimport_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativev4compiler_p.h>
+
+#include <QtCore/qvector.h>
+
+// #define DEBUG_IR_STRUCTURE
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTextStream;
+class QDeclarativeType;
+
+namespace QDeclarativeJS {
+
+namespace IR {
+
+struct BasicBlock;
+struct Function;
+struct Module;
+
+struct Stmt;
+struct Expr;
+
+// expressions
+struct Const;
+struct String;
+struct Name;
+struct Temp;
+struct Unop;
+struct Binop;
+struct Call;
+
+// statements
+struct Exp;
+struct Move;
+struct Jump;
+struct CJump;
+struct Ret;
+
+enum AluOp {
+ OpInvalid = 0,
+
+ OpIfTrue,
+ OpNot,
+ OpUMinus,
+ OpUPlus,
+ OpCompl,
+
+ OpBitAnd,
+ OpBitOr,
+ OpBitXor,
+
+ OpAdd,
+ OpSub,
+ OpMul,
+ OpDiv,
+ OpMod,
+
+ OpLShift,
+ OpRShift,
+ OpURShift,
+
+ OpGt,
+ OpLt,
+ OpGe,
+ OpLe,
+ OpEqual,
+ OpNotEqual,
+ OpStrictEqual,
+ OpStrictNotEqual,
+
+ OpAnd,
+ OpOr
+};
+AluOp binaryOperator(int op);
+
+enum Type {
+ InvalidType,
+ UndefinedType,
+ NullType,
+ VoidType,
+ StringType,
+ UrlType,
+ AnchorLineType,
+ SGAnchorLineType,
+ AttachType,
+ ObjectType,
+
+ FirstNumberType,
+ BoolType = FirstNumberType,
+ IntType,
+ RealType,
+ RealNaNType
+};
+Type maxType(IR::Type left, IR::Type right);
+
+struct ExprVisitor {
+ virtual ~ExprVisitor() {}
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitTemp(Temp *) {}
+ virtual void visitUnop(Unop *) {}
+ virtual void visitBinop(Binop *) {}
+ virtual void visitCall(Call *) {}
+};
+
+struct StmtVisitor {
+ virtual ~StmtVisitor() {}
+ virtual void visitExp(Exp *) {}
+ virtual void visitMove(Move *) {}
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *) {}
+ virtual void visitRet(Ret *) {}
+};
+
+struct Expr {
+ Type type;
+
+ Expr(Type type): type(type) {}
+ virtual ~Expr() {}
+ virtual void accept(ExprVisitor *) = 0;
+ virtual Const *asConst() { return 0; }
+ virtual String *asString() { return 0; }
+ virtual Name *asName() { return 0; }
+ virtual Temp *asTemp() { return 0; }
+ virtual Unop *asUnop() { return 0; }
+ virtual Binop *asBinop() { return 0; }
+ virtual Call *asCall() { return 0; }
+ virtual void dump(QTextStream &out) = 0;
+};
+
+struct Const: Expr {
+ double value;
+ Const(Type type, double value): Expr(type), value(value) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitConst(this); }
+ virtual Const *asConst() { return this; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct String: Expr {
+ QString value;
+ String(const QString &value): Expr(StringType), value(value) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitString(this); }
+ virtual String *asString() { return this; }
+
+ virtual void dump(QTextStream &out);
+ static QString escape(const QString &s);
+};
+
+enum BuiltinSymbol {
+ NoBuiltinSymbol,
+ MathSinBultinFunction,
+ MathCosBultinFunction,
+ MathRoundBultinFunction,
+ MathFloorBultinFunction,
+
+ MathPIBuiltinConstant
+};
+
+struct Name: Expr {
+ enum Symbol {
+ Unbound,
+ IdObject, // This is a load of a id object. Storage will always be IdStorage
+ AttachType, // This is a load of an attached object
+ Object, // XXX what is this for?
+ Property, // This is a load of a regular property
+ Slot // XXX what is this for?
+ };
+
+ enum Storage {
+ MemberStorage, // This is a property of a previously fetched object
+ IdStorage, // This is a load of a id object. Symbol will always be IdObject
+ RootStorage, // This is a property of the root object
+ ScopeStorage // This is a property of the scope object
+ };
+
+ Name *base;
+ QString id;
+ Symbol symbol;
+ union {
+ void *ptr;
+ const QMetaObject *meta;
+ const QDeclarativeType *declarativeType;
+ const QDeclarativeParser::Object *idObject;
+ };
+ int index;
+ Storage storage;
+ BuiltinSymbol builtin;
+ quint32 line;
+ quint32 column;
+
+ Name(Name *base, Type type, const QString &id, Symbol symbol, quint32 line, quint32 column);
+
+ inline bool is(Symbol s) const { return s == symbol; }
+ inline bool isNot(Symbol s) const { return s != symbol; }
+
+ virtual void accept(ExprVisitor *v) { v->visitName(this); }
+ virtual Name *asName() { return this; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct Temp: Expr {
+ int index;
+ Temp(Type type, int index): Expr(type), index(index) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
+ virtual Temp *asTemp() { return this; }
+
+ virtual void dump(QTextStream &out);
+};
+
+struct Unop: Expr {
+ AluOp op;
+ Expr *expr;
+
+ Unop(AluOp op, Expr *expr)
+ : Expr(typeForOp(op, expr)), op(op), expr(expr) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitUnop(this); }
+ virtual Unop *asUnop() { return this; }
+
+ virtual void dump(QTextStream &out);
+
+private:
+ static Type typeForOp(AluOp op, Expr *expr);
+};
+
+struct Binop: Expr {
+ AluOp op;
+ Expr *left;
+ Expr *right;
+ Binop(AluOp op, Expr *left, Expr *right)
+ : Expr(typeForOp(op, left, right)), op(op), left(left), right(right) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitBinop(this); }
+ virtual Binop *asBinop() { return this; }
+
+ virtual void dump(QTextStream &out);
+
+private:
+ static Type typeForOp(AluOp op, Expr *left, Expr *right);
+};
+
+struct Call: Expr {
+ Expr *base;
+ QVector<Expr *> args;
+
+ Call(Expr *base, const QVector<Expr *> &args)
+ : Expr(typeForFunction(base)), base(base), args(args) {}
+
+ virtual void accept(ExprVisitor *v) { v->visitCall(this); }
+ virtual Call *asCall() { return this; }
+
+ virtual void dump(QTextStream &out);
+
+private:
+ static Type typeForFunction(Expr *base);
+};
+
+struct Stmt {
+ enum Mode {
+ HIR,
+ MIR
+ };
+
+ virtual ~Stmt() {}
+ virtual Stmt *asTerminator() { return 0; }
+
+ virtual void accept(StmtVisitor *) = 0;
+ virtual Exp *asExp() { return 0; }
+ virtual Move *asMove() { return 0; }
+ virtual Jump *asJump() { return 0; }
+ virtual CJump *asCJump() { return 0; }
+ virtual Ret *asRet() { return 0; }
+ virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
+};
+
+struct Exp: Stmt {
+ Expr *expr;
+ Exp(Expr *expr): expr(expr) {}
+
+ virtual void accept(StmtVisitor *v) { v->visitExp(this); }
+ virtual Exp *asExp() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Move: Stmt {
+ Expr *target;
+ Expr *source;
+ bool isMoveForReturn;
+ Move(Expr *target, Expr *source, bool isMoveForReturn): target(target), source(source), isMoveForReturn(isMoveForReturn) {}
+
+ virtual void accept(StmtVisitor *v) { v->visitMove(this); }
+ virtual Move *asMove() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Jump: Stmt {
+ BasicBlock *target;
+ Jump(BasicBlock *target): target(target) {}
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitJump(this); }
+ virtual Jump *asJump() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
+struct CJump: Stmt {
+ Expr *cond;
+ BasicBlock *iftrue;
+ BasicBlock *iffalse;
+ CJump(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+ : cond(cond), iftrue(iftrue), iffalse(iffalse) {}
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitCJump(this); }
+ virtual CJump *asCJump() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
+struct Ret: Stmt {
+ Expr *expr;
+ Type type;
+ quint32 line;
+ quint32 column;
+ Ret(Expr *expr, Type type, quint32 line, quint32 column): expr(expr), type(type), line(line), column(column) {}
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitRet(this); }
+ virtual Ret *asRet() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Function {
+ Module *module;
+ const NameId *name;
+ int tempCount;
+ QVector<BasicBlock *> basicBlocks;
+ QVector<Expr *> temps;
+
+ template <typename BB> inline BB i(BB i) { basicBlocks.append(i); return i; }
+ template <typename E> inline E e(E e) { temps.append(e); return e; }
+
+ Function(Module *module, const NameId *name = 0): module(module), name(name), tempCount(0) {}
+ ~Function();
+
+ BasicBlock *newBasicBlock();
+
+ virtual void dump(QTextStream &out);
+};
+
+struct BasicBlock {
+ Function *function;
+ int index;
+ QVector<Stmt *> statements;
+ int offset;
+
+ BasicBlock(Function *function, int index): function(function), index(index), offset(-1) {}
+ ~BasicBlock() { qDeleteAll(statements); }
+
+ template <typename Instr> inline Instr i(Instr i) { statements.append(i); return i; }
+
+ inline bool isEmpty() const {
+ return statements.isEmpty();
+ }
+
+ inline Stmt *terminator() const {
+ if (! statements.isEmpty() && statements.last()->asTerminator() != 0)
+ return statements.last();
+ return 0;
+ }
+
+ inline bool isTerminated() const {
+ if (terminator() != 0)
+ return true;
+ return false;
+ }
+
+ Temp *TEMP(Type type, int index);
+ Temp *TEMP(Type type);
+
+ Expr *CONST(double value);
+ Expr *CONST(Type type, double value);
+ Expr *STRING(const QString &value);
+
+ Name *NAME(const QString &id, quint32 line, quint32 column);
+ Name *NAME(Name *base, const QString &id, quint32 line, quint32 column);
+ Name *SYMBOL(Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage, quint32 line, quint32 column);
+ Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, quint32 line, quint32 column);
+ Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, int index, Name::Storage storage, quint32 line, quint32 column);
+ Name *ID_OBJECT(const QString &id, const QDeclarativeParser::Object *object, quint32 line, quint32 column);
+ Name *ATTACH_TYPE(const QString &id, const QDeclarativeType *attachType, Name::Storage storage, quint32 line, quint32 column);
+
+ Expr *UNOP(AluOp op, Expr *expr);
+ Expr *BINOP(AluOp op, Expr *left, Expr *right);
+ Expr *CALL(Expr *base, const QVector<Expr *> &args);
+
+ Stmt *EXP(Expr *expr);
+ Stmt *MOVE(Expr *target, Expr *source, bool = false);
+
+ Stmt *JUMP(BasicBlock *target);
+ Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
+ Stmt *RET(Expr *expr, Type type, quint32 line, quint32 column);
+
+ virtual void dump(QTextStream &out);
+};
+
+struct Module {
+ QVector<Function *> functions;
+
+ Module() {}
+ ~Module() { qDeleteAll(functions); }
+
+ template <typename BB> inline BB i(BB i) { functions.append(i); return i; }
+
+ Function *newFunction(const NameId *name = 0) { return i(new Function(this, name)); }
+
+ virtual void dump(QTextStream &out);
+};
+
+#ifdef DEBUG_IR_STRUCTURE
+struct IRDump : public ExprVisitor,
+ public StmtVisitor
+{
+public:
+ IRDump();
+
+ void expression(QDeclarativeJS::IR::Expr *);
+ void basicblock(QDeclarativeJS::IR::BasicBlock *);
+ void statement(QDeclarativeJS::IR::Stmt *);
+ void function(QDeclarativeJS::IR::Function *);
+protected:
+
+ const char *indent();
+
+ //
+ // expressions
+ //
+ virtual void visitConst(QDeclarativeJS::IR::Const *e);
+ virtual void visitString(QDeclarativeJS::IR::String *e);
+ virtual void visitName(QDeclarativeJS::IR::Name *e);
+ virtual void visitTemp(QDeclarativeJS::IR::Temp *e);
+ virtual void visitUnop(QDeclarativeJS::IR::Unop *e);
+ virtual void visitBinop(QDeclarativeJS::IR::Binop *e);
+ virtual void visitCall(QDeclarativeJS::IR::Call *e);
+
+ //
+ // statements
+ //
+ virtual void visitExp(QDeclarativeJS::IR::Exp *s);
+ virtual void visitMove(QDeclarativeJS::IR::Move *s);
+ virtual void visitJump(QDeclarativeJS::IR::Jump *s);
+ virtual void visitCJump(QDeclarativeJS::IR::CJump *s);
+ virtual void visitRet(QDeclarativeJS::IR::Ret *s);
+
+private:
+ int indentSize;
+ QByteArray indentData;
+ void inc();
+ void dec();
+};
+#endif
+
+} // end of namespace IR
+
+} // end of namespace QDeclarativeJS
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4IR_P_H
diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
new file mode 100644
index 0000000000..103d5ba0df
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
@@ -0,0 +1,1315 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativev4irbuilder_p.h"
+
+#include <private/qdeclarativeglobalscriptclass_p.h> // For illegalNames
+#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
+#include <private/qsganchors_p_p.h> // For AnchorLine
+#include <private/qdeclarativetypenamecache_p.h>
+
+DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
+
+QT_BEGIN_NAMESPACE
+
+using namespace QDeclarativeJS;
+
+static IR::Type irTypeFromVariantType(int t, QDeclarativeEnginePrivate *engine, const QMetaObject *meta)
+{
+ switch (t) {
+ case QMetaType::Bool:
+ return IR::BoolType;
+
+ case QMetaType::Int:
+ return IR::IntType;
+
+ case QMetaType::QReal:
+ return IR::RealType;
+
+ case QMetaType::QString:
+ return IR::StringType;
+
+ case QMetaType::QUrl:
+ return IR::UrlType;
+
+ default:
+ if (t == qMetaTypeId<QDeclarativeAnchorLine>())
+ return IR::AnchorLineType;
+ else if (t == qMetaTypeId<QSGAnchorLine>())
+ return IR::SGAnchorLineType;
+ else if (const QMetaObject *m = engine->metaObjectForType(t)) {
+ meta = m;
+ return IR::ObjectType;
+ }
+
+ return IR::InvalidType;
+ }
+}
+
+QDeclarativeV4IRBuilder::QDeclarativeV4IRBuilder(const QDeclarativeV4Compiler::Expression *expr,
+ QDeclarativeEnginePrivate *engine)
+: m_expression(expr), m_engine(engine), _module(0), _function(0), _block(0), _discard(false)
+{
+}
+
+QDeclarativeJS::IR::Function *
+QDeclarativeV4IRBuilder::operator()(QDeclarativeJS::IR::Module *module,
+ QDeclarativeJS::AST::Node *ast)
+{
+ bool discarded = false;
+
+ qSwap(_module, module);
+
+ IR::Function *function = _module->newFunction();
+ IR::BasicBlock *block = function->newBasicBlock();
+
+ qSwap(_discard, discarded);
+ qSwap(_function, function);
+ qSwap(_block, block);
+
+ ExprResult r;
+ AST::SourceLocation location;
+ if (AST::ExpressionNode *asExpr = ast->expressionCast()) {
+ r = expression(asExpr);
+ location = asExpr->firstSourceLocation();
+ } else if (AST::Statement *asStmt = ast->statementCast()) {
+ r = statement(asStmt);
+ location = asStmt->firstSourceLocation();
+ }
+
+ //_block->MOVE(_block->TEMP(IR::InvalidType), r.code);
+ if (r.code) {
+ const QMetaObject *m = 0;
+ const IR::Type targetType = irTypeFromVariantType(m_expression->property->type, m_engine, m);
+ if (targetType != r.type()) {
+ IR::Expr *x = _block->TEMP(targetType);
+ _block->MOVE(x, r, true);
+ r.code = x;
+ }
+ _block->RET(r.code, targetType, location.startLine, location.startColumn);
+ }
+
+ qSwap(_block, block);
+ qSwap(_function, function);
+ qSwap(_discard, discarded);
+
+ qSwap(_module, module);
+
+ return discarded?0:function;
+}
+
+bool QDeclarativeV4IRBuilder::buildName(QStringList &name,
+ AST::Node *node,
+ QList<AST::ExpressionNode *> *nodes)
+{
+ if (node->kind == AST::Node::Kind_IdentifierExpression) {
+ name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
+ if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
+ } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
+ AST::FieldMemberExpression *expr =
+ static_cast<AST::FieldMemberExpression *>(node);
+
+ if (!buildName(name, expr->base, nodes))
+ return false;
+
+ name << expr->name->asString();
+ if (nodes) *nodes << expr;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void QDeclarativeV4IRBuilder::discard()
+{
+ _discard = true;
+}
+
+QDeclarativeV4IRBuilder::ExprResult
+QDeclarativeV4IRBuilder::expression(AST::ExpressionNode *ast)
+{
+ ExprResult r;
+ if (ast) {
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+
+ if (r.is(IR::InvalidType))
+ discard();
+ else {
+ Q_ASSERT(r.hint == r.format);
+ }
+ }
+
+ return r;
+}
+
+void QDeclarativeV4IRBuilder::condition(AST::ExpressionNode *ast, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
+{
+ if (! ast)
+ return;
+ ExprResult r(iftrue, iffalse);
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+
+ if (r.format != ExprResult::cx) {
+ if (! r.code)
+ discard();
+
+ Q_ASSERT(r.hint == ExprResult::cx);
+ Q_ASSERT(r.format == ExprResult::ex);
+
+ if (r.type() != IR::BoolType) {
+ IR::Temp *t = _block->TEMP(IR::BoolType);
+ _block->MOVE(t, r);
+ r = t;
+ }
+
+ _block->CJUMP(_block->UNOP(IR::OpIfTrue, r), iftrue, iffalse);
+ }
+}
+
+QDeclarativeV4IRBuilder::ExprResult
+QDeclarativeV4IRBuilder::statement(AST::Statement *ast)
+{
+ ExprResult r;
+ if (ast) {
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+
+ if (r.is(IR::InvalidType))
+ discard();
+ else {
+ Q_ASSERT(r.hint == r.format);
+ }
+ }
+
+ return r;
+}
+
+void QDeclarativeV4IRBuilder::sourceElement(AST::SourceElement *ast)
+{
+ accept(ast);
+}
+
+void QDeclarativeV4IRBuilder::implicitCvt(ExprResult &expr, IR::Type type)
+{
+ if (expr.type() == type)
+ return; // nothing to do
+
+ IR::Expr *x = _block->TEMP(type);
+ _block->MOVE(x, expr.code);
+ expr.code = x;
+}
+
+// QML
+bool QDeclarativeV4IRBuilder::visit(AST::UiProgram *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiImportList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiImport *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiPublicMember *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiSourceElement *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectDefinition *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectInitializer *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiScriptBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiArrayBinding *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiObjectMemberList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiArrayMemberList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiQualifiedId *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiSignature *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiFormalList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UiFormal *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// JS
+bool QDeclarativeV4IRBuilder::visit(AST::Program *ast)
+{
+ _function = _module->newFunction();
+ _block = _function->newBasicBlock();
+ accept(ast->elements);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::SourceElements *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionSourceElement *)
+{
+ return true; // look inside
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StatementSourceElement *)
+{
+ return true; // look inside
+}
+
+// object literals
+bool QDeclarativeV4IRBuilder::visit(AST::PropertyNameAndValueList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::IdentifierPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StringLiteralPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NumericLiteralPropertyName *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// array literals
+bool QDeclarativeV4IRBuilder::visit(AST::ElementList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Elision *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+
+// function calls
+bool QDeclarativeV4IRBuilder::visit(AST::ArgumentList *)
+{
+ Q_ASSERT(!"unreachable");
+ return false;
+}
+
+// expressions
+bool QDeclarativeV4IRBuilder::visit(AST::ObjectLiteral *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ArrayLiteral *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ThisExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::IdentifierExpression *ast)
+{
+ const quint32 line = ast->identifierToken.startLine;
+ const quint32 column = ast->identifierToken.startColumn;
+
+ const QString name = ast->name->asString();
+
+ if (name.at(0) == QLatin1Char('u') && name.length() == 9 && name == QLatin1String("undefined")) {
+ _expr.code = _block->CONST(IR::UndefinedType, 0); // ### undefined value
+ } else if(m_engine->globalClass->illegalNames().contains(name) ) {
+ if (qmlVerboseCompiler()) qWarning() << "*** illegal symbol:" << name;
+ return false;
+ } else if (const QDeclarativeParser::Object *obj = m_expression->ids.value(name)) {
+ IR::Name *code = _block->ID_OBJECT(name, obj, line, column);
+ if (obj == m_expression->component)
+ code->storage = IR::Name::RootStorage;
+ _expr.code = code;
+ } else if (QDeclarativeTypeNameCache::Data *typeNameData = m_expression->importCache->data(name)) {
+ if (typeNameData->importedScriptIndex != -1) {
+ // We don't support invoking imported scripts
+ } else if (typeNameData->type) {
+ _expr.code = _block->ATTACH_TYPE(name, typeNameData->type, IR::Name::ScopeStorage, line, column);
+ } else if (typeNameData->typeNamespace) {
+ // We don't support namespaces
+ } else {
+ Q_ASSERT(!"Unreachable");
+ }
+ } else {
+ bool found = false;
+
+ if (m_expression->context != m_expression->component) {
+ // RootStorage is more efficient than ScopeStorage, so prefer that if they are the same
+ QDeclarativePropertyCache *cache = m_expression->context->synthCache;
+ const QMetaObject *metaObject = m_expression->context->metaObject();
+ if (!cache) cache = m_engine->cache(metaObject);
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (data && data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ if (data && !(data->flags & QDeclarativePropertyCache::Data::IsFunction)) {
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject);
+ _expr.code = _block->SYMBOL(irType, name, metaObject, data->coreIndex, IR::Name::ScopeStorage, line, column);
+ found = true;
+ }
+ }
+
+ if (!found) {
+ QDeclarativePropertyCache *cache = m_expression->component->synthCache;
+ const QMetaObject *metaObject = m_expression->component->metaObject();
+ if (!cache) cache = m_engine->cache(metaObject);
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (data && data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ if (data && !(data->flags & QDeclarativePropertyCache::Data::IsFunction)) {
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject);
+ _expr.code = _block->SYMBOL(irType, name, metaObject, data->coreIndex, IR::Name::RootStorage, line, column);
+ found = true;
+ }
+ }
+
+ if (!found && qmlVerboseCompiler())
+ qWarning() << "*** unknown symbol:" << name;
+ }
+
+ if (_expr.code && _expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+
+ if (_expr.type() != IR::BoolType) {
+ IR::Temp *t = _block->TEMP(IR::BoolType);
+ _block->MOVE(t, _expr);
+ _expr.code = t;
+ }
+
+ _block->CJUMP(_expr.code, _expr.iftrue, _expr.iffalse);
+ _expr.code = 0;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NullExpression *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::NullType, 0);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TrueLiteral *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::BoolType, 1);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FalseLiteral *)
+{
+ // ### TODO: cx format
+ _expr.code = _block->CONST(IR::BoolType, 0);
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StringLiteral *ast)
+{
+ // ### TODO: cx format
+ _expr.code = _block->STRING(ast->value->asString());
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NumericLiteral *ast)
+{
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->JUMP(ast->value ? _expr.iftrue : _expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(ast->value);
+ }
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::RegExpLiteral *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NestedExpression *)
+{
+ return true; // the value of the nested expression
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ArrayMemberExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FieldMemberExpression *ast)
+{
+ if (IR::Expr *left = expression(ast->base)) {
+ if (IR::Name *baseName = left->asName()) {
+ const quint32 line = ast->identifierToken.startLine;
+ const quint32 column = ast->identifierToken.startColumn;
+
+ QString name = ast->name->asString();
+
+ switch(baseName->symbol) {
+ case IR::Name::Unbound:
+ break;
+
+ case IR::Name::AttachType:
+ if (name.at(0).isUpper()) {
+ QByteArray utf8Name = name.toUtf8();
+ const char *enumName = utf8Name.constData();
+
+ const QMetaObject *meta = baseName->declarativeType->metaObject();
+ bool found = false;
+ for (int ii = 0; !found && ii < meta->enumeratorCount(); ++ii) {
+ QMetaEnum e = meta->enumerator(ii);
+ for (int jj = 0; !found && jj < e.keyCount(); ++jj) {
+ if (0 == strcmp(e.key(jj), enumName)) {
+ found = true;
+ _expr.code = _block->CONST(IR::IntType, e.value(jj));
+ }
+ }
+ }
+
+ if (!found && qmlVerboseCompiler())
+ qWarning() << "*** unresolved enum:"
+ << (baseName->id + QLatin1String(".") + ast->name->asString());
+ } else if(const QMetaObject *attachedMeta = baseName->declarativeType->attachedPropertiesType()) {
+ QDeclarativePropertyCache *cache = m_engine->cache(attachedMeta);
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction)
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if(!(data->flags & QDeclarativePropertyCache::Data::IsFinal)) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** non-final attached property:"
+ << (baseName->id + QLatin1String(".") + ast->name->asString());
+ return false; // We don't know enough about this property
+ }
+
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, attachedMeta);
+ _expr.code = _block->SYMBOL(baseName, irType, name, attachedMeta, data->coreIndex, line, column);
+ }
+ break;
+
+ case IR::Name::IdObject: {
+ const QDeclarativeParser::Object *idObject = baseName->idObject;
+ QDeclarativePropertyCache *cache =
+ idObject->synthCache?idObject->synthCache:m_engine->cache(idObject->metaObject());
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction)
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if (data->revision != 0) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** versioned symbol:" << name;
+ discard();
+ return false;
+ }
+
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, idObject->metaObject());
+ _expr.code = _block->SYMBOL(baseName, irType, name,
+ idObject->metaObject(), data->coreIndex, line, column);
+ }
+ break;
+
+ case IR::Name::Property:
+ if (baseName->type == IR::ObjectType) {
+ const QMetaObject *m =
+ m_engine->metaObjectForType(baseName->meta->property(baseName->index).userType());
+ QDeclarativePropertyCache *cache = m_engine->cache(m);
+
+ QDeclarativePropertyCache::Data *data = cache->property(name);
+
+ if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction)
+ return false; // Don't support methods (or non-existing properties ;)
+
+ if(!(data->flags & QDeclarativePropertyCache::Data::IsFinal)) {
+ if (qmlVerboseCompiler())
+ qWarning() << "*** non-final property access:"
+ << (baseName->id + QLatin1String(".") + ast->name->asString());
+ return false; // We don't know enough about this property
+ }
+
+ IR::Type irType = irTypeFromVariantType(data->propType, m_engine, baseName->meta);
+ _expr.code = _block->SYMBOL(baseName, irType, name,
+ baseName->meta, data->coreIndex, line, column);
+ }
+ break;
+
+ case IR::Name::Object:
+ case IR::Name::Slot:
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NewMemberExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NewExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CallExpression *ast)
+{
+ QStringList names;
+ QList<AST::ExpressionNode *> nameNodes;
+ if (buildName(names, ast->base, &nameNodes)) {
+ //ExprResult base = expression(ast->base);
+ const QString id = names.join(QLatin1String("."));
+ const quint32 line = nameNodes.last()->firstSourceLocation().startLine;
+ const quint32 column = nameNodes.last()->firstSourceLocation().startColumn;
+ IR::Expr *base = _block->NAME(id, line, column);
+
+ QVector<IR::Expr *> args;
+ for (AST::ArgumentList *it = ast->arguments; it; it = it->next)
+ args.append(expression(it->expression));
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+ IR::Expr *call = _block->CALL(base, args);
+ _block->MOVE(r, call);
+ r->type = call->type;
+ _expr.code = r;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PostIncrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PostDecrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DeleteExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VoidExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TypeOfExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PreIncrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::PreDecrementExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UnaryPlusExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+ if (expr.isNot(IR::InvalidType)) {
+ if (expr.code->asConst() != 0) {
+ _expr = expr;
+ return false;
+ }
+
+ IR::Expr *code = _block->UNOP(IR::OpUPlus, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::UnaryMinusExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+ if (expr.isNot(IR::InvalidType)) {
+ if (IR::Const *c = expr.code->asConst()) {
+ _expr = expr;
+ _expr.code = _block->CONST(-c->value);
+ return false;
+ }
+
+ IR::Expr *code = _block->UNOP(IR::OpUMinus, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TildeExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+ if (expr.isNot(IR::InvalidType)) {
+ if (IR::Const *c = expr.code->asConst()) {
+ _expr = expr;
+ _expr.code = _block->CONST(~int(c->value));
+ return false;
+ }
+ IR::Expr *code = _block->UNOP(IR::OpCompl, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::NotExpression *ast)
+{
+ ExprResult expr = expression(ast->expression);
+
+ if (expr.isNot(IR::InvalidType)) {
+ if (IR::Const *c = expr.code->asConst()) {
+ _expr = expr;
+ _expr.code = _block->CONST(!c->value);
+ return false;
+ }
+
+ IR::Expr *code = _block->UNOP(IR::OpNot, expr);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr, code);
+
+ } else if (expr.hint == ExprResult::cx) {
+ expr.format = ExprResult::cx;
+ _block->CJUMP(_block->UNOP(IR::OpNot, expr), _expr.iftrue, _expr.iffalse);
+ return false;
+ }
+
+ return false;
+}
+
+void QDeclarativeV4IRBuilder::binop(AST::BinaryExpression *ast, ExprResult left, ExprResult right)
+{
+ if (IR::Type t = maxType(left.type(), right.type())) {
+ implicitCvt(left, t);
+ implicitCvt(right, t);
+
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->CJUMP(_block->BINOP(IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse);
+ } else {
+ IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr.code, code);
+ }
+ }
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::BinaryExpression *ast)
+{
+ switch (ast->op) {
+ case QSOperator::And: {
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+
+ Q_ASSERT(_expr.iffalse != 0);
+ Q_ASSERT(_expr.iftrue != 0);
+
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ condition(ast->left, iftrue, _expr.iffalse);
+
+ _block = iftrue;
+ condition(ast->right, _expr.iftrue, _expr.iffalse);
+ } else {
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *iffalse = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ condition(ast->left, iftrue, iffalse);
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+
+ _block = iffalse;
+ _block->MOVE(r, _block->CONST(0)); // ### use the right null value
+ _block->JUMP(endif);
+
+ _block = iftrue;
+ ExprResult right = expression(ast->right);
+ _block->MOVE(r, right);
+ _block->JUMP(endif);
+
+ _block = endif;
+
+ r->type = right.type(); // ### not exactly, it can be IR::BoolType.
+ _expr.code = r;
+ }
+ } break;
+
+ case QSOperator::Or: {
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ ExprResult left = expression(ast->left);
+ IR::Temp *r = _block->TEMP(left.type());
+ _block->MOVE(r, left);
+
+ IR::Expr *cond = r;
+ if (r->type != IR::BoolType) {
+ cond = _block->TEMP(IR::BoolType);
+ _block->MOVE(cond, r);
+ }
+
+ _block->CJUMP(_block->UNOP(IR::OpNot, cond), iftrue, endif);
+
+ _block = iftrue;
+ ExprResult right = expression(ast->right);
+ _block->MOVE(r, right);
+
+ if (left.type() != right.type())
+ discard();
+
+ _expr.code = r;
+
+ _block = endif;
+ } break;
+
+ case QSOperator::Lt:
+ case QSOperator::Gt:
+ case QSOperator::Le:
+ case QSOperator::Ge: {
+ ExprResult left = expression(ast->left);
+ ExprResult right = expression(ast->right);
+ if (left.type() == IR::StringType && right.type() == IR::StringType) {
+ binop(ast, left, right);
+ } else if (left.isValid() && right.isValid()) {
+ implicitCvt(left, IR::RealType);
+ implicitCvt(right, IR::RealType);
+ binop(ast, left, right);
+ }
+ } break;
+
+ case QSOperator::NotEqual:
+ case QSOperator::Equal: {
+ ExprResult left = expression(ast->left);
+ ExprResult right = expression(ast->right);
+ if ((left.type() == IR::NullType || left.type() == IR::UndefinedType) &&
+ (right.type() == IR::NullType || right.type() == IR::UndefinedType)) {
+ const bool isEq = ast->op == QSOperator::Equal;
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->JUMP(isEq ? _expr.iftrue : _expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(IR::BoolType, isEq ? 1 : 0);
+ }
+ } else if ((left.type() == IR::StringType && right.type() >= IR::FirstNumberType) ||
+ (left.type() >= IR::FirstNumberType && right.type() == IR::StringType)) {
+ implicitCvt(left, IR::RealType);
+ implicitCvt(right, IR::RealType);
+ binop(ast, left, right);
+ } else if (left.type() == IR::BoolType || right.type() == IR::BoolType) {
+ implicitCvt(left, IR::BoolType);
+ implicitCvt(right, IR::BoolType);
+ } else if (left.isValid() && right.isValid()) {
+ binop(ast, left, right);
+ }
+ } break;
+
+ case QSOperator::StrictEqual:
+ case QSOperator::StrictNotEqual: {
+ ExprResult left = expression(ast->left);
+ ExprResult right = expression(ast->right);
+ if (left.type() == right.type()) {
+ binop(ast, left, right);
+ } else if (left.type() >= IR::BoolType && right.type() >= IR::BoolType) {
+ // left and right have numeric type (int or real)
+ binop(ast, left, right);
+ } else if (left.isValid() && right.isValid()) {
+ const bool isEq = ast->op == QSOperator::StrictEqual;
+ if (_expr.hint == ExprResult::cx) {
+ _expr.format = ExprResult::cx;
+ _block->JUMP(isEq ? _expr.iftrue : _expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(IR::BoolType, isEq ? 1 : 0);
+ }
+ }
+ } break;
+
+ case QSOperator::BitAnd:
+ case QSOperator::BitOr:
+ case QSOperator::BitXor:
+ case QSOperator::LShift:
+ case QSOperator::RShift:
+ case QSOperator::URShift: {
+ ExprResult left = expression(ast->left);
+ if (left.is(IR::InvalidType))
+ return false;
+
+ ExprResult right = expression(ast->right);
+ if (right.is(IR::InvalidType))
+ return false;
+
+ implicitCvt(left, IR::IntType);
+ implicitCvt(right, IR::IntType);
+
+ IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr.code, code);
+
+ } break;
+
+ case QSOperator::Add: {
+ ExprResult left = expression(ast->left);
+ if (left.is(IR::InvalidType))
+ return false;
+
+ ExprResult right = expression(ast->right);
+ if (right.is(IR::InvalidType))
+ return false;
+
+ if (left.isPrimitive() && right.isPrimitive()) {
+ if (left.type() == IR::StringType || right.type() == IR::StringType) {
+ implicitCvt(left, IR::StringType);
+ implicitCvt(right, IR::StringType);
+ }
+ binop(ast, left, right);
+ }
+ } break;
+
+ case QSOperator::Div:
+ case QSOperator::Mod:
+ case QSOperator::Mul:
+ case QSOperator::Sub: {
+ ExprResult left = expression(ast->left);
+ if (left.is(IR::InvalidType))
+ return false;
+
+ ExprResult right = expression(ast->right);
+ if (right.is(IR::InvalidType))
+ return false;
+
+ IR::Type t = maxType(left.type(), right.type());
+ if (t >= IR::FirstNumberType) {
+ implicitCvt(left, IR::RealType);
+ implicitCvt(right, IR::RealType);
+
+ IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ _expr.code = _block->TEMP(code->type);
+ _block->MOVE(_expr.code, code);
+ }
+ } break;
+
+ case QSOperator::In:
+ case QSOperator::InstanceOf:
+ case QSOperator::Assign:
+ case QSOperator::InplaceAnd:
+ case QSOperator::InplaceSub:
+ case QSOperator::InplaceDiv:
+ case QSOperator::InplaceAdd:
+ case QSOperator::InplaceLeftShift:
+ case QSOperator::InplaceMod:
+ case QSOperator::InplaceMul:
+ case QSOperator::InplaceOr:
+ case QSOperator::InplaceRightShift:
+ case QSOperator::InplaceURightShift:
+ case QSOperator::InplaceXor:
+ // yup, we don't do those.
+ break;
+ } // switch
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ConditionalExpression *ast)
+{
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *iffalse = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ condition(ast->expression, iftrue, iffalse);
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+
+ qSwap(_block, iftrue);
+ ExprResult ok = expression(ast->ok);
+ _block->MOVE(r, ok);
+ _block->JUMP(endif);
+ qSwap(_block, iftrue);
+
+ qSwap(_block, iffalse);
+ ExprResult ko = expression(ast->ko);
+ _block->MOVE(r, ko);
+ _block->JUMP(endif);
+ qSwap(_block, iffalse);
+
+ r->type = maxType(ok.type(), ko.type());
+ _expr.code = r;
+
+ _block = endif;
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Expression *ast)
+{
+ _block->EXP(expression(ast->left));
+ _expr = expression(ast->right);
+
+ return false;
+}
+
+
+// statements
+bool QDeclarativeV4IRBuilder::visit(AST::Block *ast)
+{
+ if (ast->statements && ! ast->statements->next) {
+ // we have one and only one statement
+ accept(ast->statements->statement);
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::StatementList *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VariableStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VariableDeclarationList *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::VariableDeclaration *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::EmptyStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ExpressionStatement *ast)
+{
+ if (ast->expression) {
+ // return the value of this expression
+ return true;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::IfStatement *ast)
+{
+ if (! ast->ko) {
+ // This is an if statement without an else branch.
+ discard();
+ } else {
+ IR::BasicBlock *iftrue = _function->newBasicBlock();
+ IR::BasicBlock *iffalse = _function->newBasicBlock();
+ IR::BasicBlock *endif = _function->newBasicBlock();
+
+ condition(ast->expression, iftrue, iffalse);
+
+ IR::Temp *r = _block->TEMP(IR::InvalidType);
+
+ qSwap(_block, iftrue);
+ ExprResult ok = statement(ast->ok);
+ _block->MOVE(r, ok);
+ _block->JUMP(endif);
+ qSwap(_block, iftrue);
+
+ qSwap(_block, iffalse);
+ ExprResult ko = statement(ast->ko);
+ _block->MOVE(r, ko);
+ _block->JUMP(endif);
+ qSwap(_block, iffalse);
+
+ r->type = maxType(ok.type(), ko.type());
+ _expr.code = r;
+
+ _block = endif;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DoWhileStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::WhileStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ForStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::LocalForStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ForEachStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::LocalForEachStatement *)
+{
+ discard();
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ContinueStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::BreakStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ReturnStatement *ast)
+{
+ if (ast->expression) {
+ // return the value of the expression
+ return true;
+ }
+
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::WithStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::SwitchStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CaseBlock *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CaseClauses *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::CaseClause *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DefaultClause *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::LabelledStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::ThrowStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::TryStatement *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Catch *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::Finally *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionDeclaration *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionExpression *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FormalParameterList *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::FunctionBody *)
+{
+ return false;
+}
+
+bool QDeclarativeV4IRBuilder::visit(AST::DebuggerStatement *)
+{
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder_p.h b/src/declarative/qml/v4/qdeclarativev4irbuilder_p.h
new file mode 100644
index 0000000000..f0bfd6624c
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4irbuilder_p.h
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4IRBUILDER_P_H
+#define QDECLARATIVEV4IRBUILDER_P_H
+
+#include <QtCore/qglobal.h>
+
+#include "qdeclarativev4ir_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeV4IRBuilder : public QDeclarativeJS::AST::Visitor
+{
+public:
+ QDeclarativeV4IRBuilder(const QDeclarativeV4Compiler::Expression *, QDeclarativeEnginePrivate *);
+
+ QDeclarativeJS::IR::Function *operator()(QDeclarativeJS::IR::Module *, QDeclarativeJS::AST::Node *);
+
+protected:
+ struct ExprResult {
+ enum Format {
+ ex, // expression
+ cx // condition
+ };
+
+ QDeclarativeJS::IR::Expr *code;
+ QDeclarativeJS::IR::BasicBlock *iftrue;
+ QDeclarativeJS::IR::BasicBlock *iffalse;
+ Format hint; // requested format
+ Format format; // instruction format
+
+ ExprResult(QDeclarativeJS::IR::Expr *expr = 0)
+ : code(expr), iftrue(0), iffalse(0), hint(ex), format(ex) {}
+
+ ExprResult(QDeclarativeJS::IR::BasicBlock *iftrue, QDeclarativeJS::IR::BasicBlock *iffalse)
+ : code(0), iftrue(iftrue), iffalse(iffalse), hint(cx), format(ex) {}
+
+ inline QDeclarativeJS::IR::Type type() const { return code ? code->type : QDeclarativeJS::IR::InvalidType; }
+
+ inline QDeclarativeJS::IR::Expr *get() const { return code; }
+ inline operator QDeclarativeJS::IR::Expr *() const { return get(); }
+ inline QDeclarativeJS::IR::Expr *operator->() const { return get(); }
+ inline bool isValid() const { return code ? code->type != QDeclarativeJS::IR::InvalidType : false; }
+ inline bool is(QDeclarativeJS::IR::Type t) const { return type() == t; }
+ inline bool isNot(QDeclarativeJS::IR::Type t) const { return type() != t; }
+
+ bool isPrimitive() const {
+ switch (type()) {
+ case QDeclarativeJS::IR::UndefinedType: // ### TODO
+ case QDeclarativeJS::IR::NullType: // ### TODO
+ case QDeclarativeJS::IR::UrlType: // ### TODO
+ return false;
+
+ case QDeclarativeJS::IR::StringType:
+ case QDeclarativeJS::IR::BoolType:
+ case QDeclarativeJS::IR::IntType:
+ case QDeclarativeJS::IR::RealType:
+ case QDeclarativeJS::IR::RealNaNType:
+ return true;
+
+ default:
+ return false;
+ } // switch
+ }
+ };
+
+ inline void accept(QDeclarativeJS::AST::Node *ast) { QDeclarativeJS::AST::Node::accept(ast, this); }
+
+ ExprResult expression(QDeclarativeJS::AST::ExpressionNode *ast);
+ ExprResult statement(QDeclarativeJS::AST::Statement *ast);
+ void sourceElement(QDeclarativeJS::AST::SourceElement *ast);
+ void condition(QDeclarativeJS::AST::ExpressionNode *ast, QDeclarativeJS::IR::BasicBlock *iftrue, QDeclarativeJS::IR::BasicBlock *iffalse);
+ void binop(QDeclarativeJS::AST::BinaryExpression *ast, ExprResult left, ExprResult right);
+
+ void implicitCvt(ExprResult &expr, QDeclarativeJS::IR::Type type);
+
+ // QML
+ virtual bool visit(QDeclarativeJS::AST::UiProgram *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiImportList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiImport *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiPublicMember *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiSourceElement *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectDefinition *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectInitializer *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectBinding *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiScriptBinding *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiArrayBinding *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiObjectMemberList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiArrayMemberList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiQualifiedId *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiSignature *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiFormalList *ast);
+ virtual bool visit(QDeclarativeJS::AST::UiFormal *ast);
+
+ // JS
+ virtual bool visit(QDeclarativeJS::AST::Program *ast);
+ virtual bool visit(QDeclarativeJS::AST::SourceElements *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionSourceElement *ast);
+ virtual bool visit(QDeclarativeJS::AST::StatementSourceElement *ast);
+
+ // object literals
+ virtual bool visit(QDeclarativeJS::AST::PropertyNameAndValueList *ast);
+ virtual bool visit(QDeclarativeJS::AST::IdentifierPropertyName *ast);
+ virtual bool visit(QDeclarativeJS::AST::StringLiteralPropertyName *ast);
+ virtual bool visit(QDeclarativeJS::AST::NumericLiteralPropertyName *ast);
+
+ // array literals
+ virtual bool visit(QDeclarativeJS::AST::ElementList *ast);
+ virtual bool visit(QDeclarativeJS::AST::Elision *ast);
+
+ // function calls
+ virtual bool visit(QDeclarativeJS::AST::ArgumentList *ast);
+
+ // expressions
+ virtual bool visit(QDeclarativeJS::AST::ObjectLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::ArrayLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::ThisExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::IdentifierExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NullExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::TrueLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::FalseLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::StringLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::NumericLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::RegExpLiteral *ast);
+ virtual bool visit(QDeclarativeJS::AST::NestedExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::ArrayMemberExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::FieldMemberExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NewMemberExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NewExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::CallExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PostIncrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PostDecrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::DeleteExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::VoidExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::TypeOfExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PreIncrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::PreDecrementExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::UnaryPlusExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::UnaryMinusExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::TildeExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::NotExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::BinaryExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::ConditionalExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::Expression *ast);
+
+ // statements
+ virtual bool visit(QDeclarativeJS::AST::Block *ast);
+ virtual bool visit(QDeclarativeJS::AST::StatementList *ast);
+ virtual bool visit(QDeclarativeJS::AST::VariableStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::VariableDeclarationList *ast);
+ virtual bool visit(QDeclarativeJS::AST::VariableDeclaration *ast);
+ virtual bool visit(QDeclarativeJS::AST::EmptyStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ExpressionStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::IfStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::DoWhileStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::WhileStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ForStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::LocalForStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ForEachStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::LocalForEachStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ContinueStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::BreakStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ReturnStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::WithStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::SwitchStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::CaseBlock *ast);
+ virtual bool visit(QDeclarativeJS::AST::CaseClauses *ast);
+ virtual bool visit(QDeclarativeJS::AST::CaseClause *ast);
+ virtual bool visit(QDeclarativeJS::AST::DefaultClause *ast);
+ virtual bool visit(QDeclarativeJS::AST::LabelledStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::ThrowStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::TryStatement *ast);
+ virtual bool visit(QDeclarativeJS::AST::Catch *ast);
+ virtual bool visit(QDeclarativeJS::AST::Finally *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionDeclaration *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionExpression *ast);
+ virtual bool visit(QDeclarativeJS::AST::FormalParameterList *ast);
+ virtual bool visit(QDeclarativeJS::AST::FunctionBody *ast);
+ virtual bool visit(QDeclarativeJS::AST::DebuggerStatement *ast);
+
+private:
+ bool buildName(QStringList &name, QDeclarativeJS::AST::Node *node,
+ QList<QDeclarativeJS::AST::ExpressionNode *> *nodes);
+ void discard();
+
+ const QDeclarativeV4Compiler::Expression *m_expression;
+ QDeclarativeEnginePrivate *m_engine;
+
+ QDeclarativeJS::IR::Module *_module;
+ QDeclarativeJS::IR::Function *_function;
+ QDeclarativeJS::IR::BasicBlock *_block;
+ bool _discard;
+
+ ExprResult _expr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4IRBUILDER_P_H
diff --git a/src/declarative/qml/v4/qdeclarativev4program_p.h b/src/declarative/qml/v4/qdeclarativev4program_p.h
new file mode 100644
index 0000000000..d036bd6f73
--- /dev/null
+++ b/src/declarative/qml/v4/qdeclarativev4program_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV4PROGRAM_P_H
+#define QDECLARATIVEV4PROGRAM_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 "qdeclarativev4instruction_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct QDeclarativeV4Program {
+ quint32 bindings;
+ quint32 dataLength;
+ quint32 signalTableOffset;
+ quint32 exceptionDataOffset;
+ quint16 subscriptions;
+ quint16 identifiers;
+ quint16 instructionCount;
+
+ struct BindingReference {
+ quint32 binding;
+ quint32 blockMask;
+ };
+
+ struct BindingReferenceList {
+ quint32 count;
+ BindingReference bindings[];
+ };
+
+ inline const char *data() const;
+ inline const char *instructions() const;
+ inline BindingReferenceList *signalTable(int signalIndex) const;
+};
+
+enum QDeclarativeRegisterType {
+ UndefinedType,
+ QObjectStarType,
+ QRealType,
+ IntType,
+ BoolType,
+
+ PODValueType,
+
+ FirstCleanupType,
+ QStringType = FirstCleanupType,
+ QUrlType,
+ QVariantType,
+};
+
+const char *QDeclarativeV4Program::data() const
+{
+ return ((const char *)this) + sizeof(QDeclarativeV4Program);
+}
+
+const char *QDeclarativeV4Program::instructions() const
+{
+ return (const char *)(data() + dataLength);
+}
+
+QDeclarativeV4Program::BindingReferenceList *QDeclarativeV4Program::signalTable(int signalIndex) const
+{
+ quint32 *signalTable = (quint32 *)(data() + signalTableOffset);
+ return (BindingReferenceList *)(signalTable + signalTable[signalIndex]);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEV4PROGRAM_P_H
+
diff --git a/src/declarative/qml/v4/v4.pri b/src/declarative/qml/v4/v4.pri
new file mode 100644
index 0000000000..085f0ae443
--- /dev/null
+++ b/src/declarative/qml/v4/v4.pri
@@ -0,0 +1,17 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qdeclarativev4compiler_p.h \
+ $$PWD/qdeclarativev4compiler_p_p.h \
+ $$PWD/qdeclarativev4ir_p.h \
+ $$PWD/qdeclarativev4irbuilder_p.h \
+ $$PWD/qdeclarativev4instruction_p.h \
+ $$PWD/qdeclarativev4bindings_p.h \
+ $$PWD/qdeclarativev4program_p.h \
+
+SOURCES += \
+ $$PWD/qdeclarativev4compiler.cpp \
+ $$PWD/qdeclarativev4ir.cpp \
+ $$PWD/qdeclarativev4irbuilder.cpp \
+ $$PWD/qdeclarativev4instruction.cpp \
+ $$PWD/qdeclarativev4bindings.cpp \
diff --git a/src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp
new file mode 100644
index 0000000000..05e502535a
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp
@@ -0,0 +1,458 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#define GL_GLEXT_PROTOTYPES
+
+#include "qsgdefaultrenderer_p.h"
+#include "qsgmaterial.h"
+
+#include <QtCore/qvarlengtharray.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/qpair.h>
+
+//#define FORCE_NO_REORDER
+
+QT_BEGIN_NAMESPACE
+
+static bool nodeLessThan(QSGGeometryNode *a, QSGGeometryNode *b)
+{
+ // Sort by clip...
+ if (a->clipList() != b->clipList())
+ return a->clipList() < b->clipList();
+
+ // Sort by material definition
+ QSGMaterialType *aDef = a->material()->type();
+ QSGMaterialType *bDef = b->material()->type();
+
+ if (aDef != bDef)
+ return aDef < bDef;
+
+ // Sort by material state
+ int cmp = a->material()->compare(b->material());
+ if (cmp != 0)
+ return cmp < 0;
+
+ return a->matrix() < b->matrix();
+}
+
+static bool nodeLessThanWithRenderOrder(QSGGeometryNode *a, QSGGeometryNode *b)
+{
+ // Sort by clip...
+ if (a->clipList() != b->clipList())
+ return a->clipList() < b->clipList();
+
+ // Sort by material definition
+ QSGMaterialType *aDef = a->material()->type();
+ QSGMaterialType *bDef = b->material()->type();
+
+ if (!(a->material()->flags() & QSGMaterial::Blending)) {
+ int aOrder = a->renderOrder();
+ int bOrder = b->renderOrder();
+ if (aOrder != bOrder)
+ return aOrder > bOrder;
+ }
+
+ if (aDef != bDef)
+ return aDef < bDef;
+
+ // Sort by material state
+ int cmp = a->material()->compare(b->material());
+ if (cmp != 0)
+ return cmp < 0;
+
+ return a->matrix() < b->matrix();
+}
+
+// Minimum heap.
+template <typename T, int prealloc = 256>
+class Heap
+{
+public:
+ void insert(const T &x);
+ const T &top() const { return v[0]; }
+ T pop();
+ bool isEmpty() const { return v.isEmpty(); }
+private:
+ static int parent(int i) { return (i - 1) >> 1; }
+ static int left(int i) { return (i << 1) | 1; }
+ static int right(int i) { return (i + 1) << 1; }
+ QVarLengthArray<T, prealloc> v;
+};
+
+template <typename T, int prealloc>
+void Heap<T, prealloc>::insert(const T &x)
+{
+ int i = v.size();
+ v.append(x);
+ while (i != 0 && v[i] < v[parent(i)]) {
+ qSwap(v[parent(i)], v[i]);
+ i = parent(i);
+ }
+}
+
+template <typename T, int prealloc>
+T Heap<T, prealloc>::pop()
+{
+ T x = top();
+ if (v.size() > 1)
+ qSwap(v[0], v[v.size() - 1]);
+ v.resize(v.size() - 1);
+ int i = 0;
+ while (left(i) < v.size()) {
+ int low = left(i);
+ if (right(i) < v.size() && v[right(i)] < v[low])
+ low = right(i);
+ if (!(v[low] < v[i]))
+ break;
+ qSwap(v[i], v[low]);
+ i = low;
+ }
+ return x;
+}
+
+
+QMLRenderer::QMLRenderer(QSGContext *context)
+ : QSGRenderer(context)
+ , m_rebuild_lists(false)
+ , m_needs_sorting(false)
+ , m_sort_front_to_back(false)
+ , m_currentRenderOrder(1)
+{
+ QStringList args = qApp->arguments();
+#if defined(QML_RUNTIME_TESTING)
+ m_render_opaque_nodes = !args.contains(QLatin1String("--no-opaque-nodes"));
+ m_render_alpha_nodes = !args.contains(QLatin1String("--no-alpha-nodes"));
+#endif
+}
+
+void QMLRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags)
+{
+ QSGRenderer::nodeChanged(node, flags);
+
+ quint32 rebuildFlags = QSGNode::DirtyNodeAdded | QSGNode::DirtyNodeRemoved | QSGNode::DirtyMaterial | QSGNode::DirtyOpacity;
+
+ if (flags & rebuildFlags)
+ m_rebuild_lists = true;
+
+ if (flags & (rebuildFlags | QSGNode::DirtyClipList))
+ m_needs_sorting = true;
+}
+
+void QMLRenderer::render()
+{
+#if defined (QML_RUNTIME_TESTING)
+ static bool dumpTree = qApp->arguments().contains(QLatin1String("--dump-tree"));
+ if (dumpTree) {
+ printf("\n\n");
+ QSGNodeDumper::dump(rootNode());
+ }
+#endif
+
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_BLEND);
+
+ glFrontFace(isMirrored() ? GL_CW : GL_CCW);
+ glDisable(GL_CULL_FACE);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(true);
+ glDepthFunc(GL_GREATER);
+#if defined(QT_OPENGL_ES)
+ glClearDepthf(0);
+#else
+ glClearDepth(0);
+#endif
+
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(m_clear_color.redF(), m_clear_color.greenF(), m_clear_color.blueF(), m_clear_color.alphaF());
+
+ bindable()->clear(clearMode());
+
+ QRect r = viewportRect();
+ glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
+ m_projectionMatrix = projectMatrix();
+ m_projectionMatrix.push();
+ m_modelViewMatrix.setToIdentity();
+
+ m_currentClip = 0;
+ glDisable(GL_STENCIL_TEST);
+
+ m_currentMaterial = 0;
+ m_currentProgram = 0;
+ m_currentMatrix = 0;
+
+ if (m_rebuild_lists) {
+ m_opaqueNodes.clear();
+ m_transparentNodes.clear();
+ m_currentRenderOrder = 1;
+ buildLists(rootNode());
+ m_rebuild_lists = false;
+ }
+
+ if (m_needs_sorting) {
+ qSort(m_opaqueNodes.begin(), m_opaqueNodes.end(),
+ m_sort_front_to_back
+ ? nodeLessThanWithRenderOrder
+ : nodeLessThan);
+ m_needs_sorting = false;
+ }
+
+ m_renderOrderMatrix.setToIdentity();
+ m_renderOrderMatrix.scale(1, 1, qreal(1) / m_currentRenderOrder);
+
+ glDisable(GL_BLEND);
+ glDepthMask(true);
+#ifdef QML_RUNTIME_TESTING
+ if (m_render_opaque_nodes)
+#endif
+ {
+#if defined (QML_RUNTIME_TESTING)
+ if (dumpTree)
+ qDebug() << "Opaque Nodes:";
+#endif
+ renderNodes(m_opaqueNodes);
+ }
+
+ glEnable(GL_BLEND);
+ glDepthMask(false);
+#ifdef QML_RUNTIME_TESTING
+ if (m_render_alpha_nodes)
+#endif
+ {
+#if defined (QML_RUNTIME_TESTING)
+ if (dumpTree)
+ qDebug() << "Alpha Nodes:";
+#endif
+ renderNodes(m_transparentNodes);
+ }
+
+ if (m_currentProgram)
+ m_currentProgram->deactivate();
+
+ m_projectionMatrix.pop();
+}
+
+class Foo : public QPair<int, QSGGeometryNode *>
+{
+public:
+ Foo() { }
+ Foo(int i, QSGGeometryNode *n) : QPair<int, QSGGeometryNode *>(i, n) { }
+ bool operator < (const Foo &other) const { return nodeLessThan(second, other.second); }
+};
+
+void QMLRenderer::setSortFrontToBackEnabled(bool sort)
+{
+ printf("setting sorting to... %d\n", sort);
+ m_sort_front_to_back = sort;
+}
+
+bool QMLRenderer::isSortFrontToBackEnabled() const
+{
+ return m_sort_front_to_back;
+}
+
+void QMLRenderer::buildLists(QSGNode *node)
+{
+ if (node->isSubtreeBlocked())
+ return;
+
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *geomNode = static_cast<QSGGeometryNode *>(node);
+ qreal opacity = geomNode->inheritedOpacity();
+ QSGMaterial *m = geomNode->activeMaterial();
+
+#ifdef FORCE_NO_REORDER
+ if (true) {
+#else
+ if ((m->flags() & QSGMaterial::Blending) || opacity < 1) {
+#endif
+ geomNode->setRenderOrder(m_currentRenderOrder - 1);
+ m_transparentNodes.append(geomNode);
+ } else {
+ geomNode->setRenderOrder(m_currentRenderOrder);
+ m_opaqueNodes.append(geomNode);
+ m_currentRenderOrder += 2;
+ }
+ }
+
+ int count = node->childCount();
+ if (!count)
+ return;
+
+#ifdef FORCE_NO_REORDER
+ static bool reorder = false;
+#else
+ static bool reorder = !qApp->arguments().contains(QLatin1String("--no-reorder"));
+#endif
+
+ if (reorder && count > 1 && (node->flags() & QSGNode::ChildrenDoNotOverloap)) {
+ QVarLengthArray<int, 16> beginIndices(count);
+ QVarLengthArray<int, 16> endIndices(count);
+ int baseCount = m_transparentNodes.size();
+ for (int i = 0; i < count; ++i) {
+ beginIndices[i] = m_transparentNodes.size();
+ buildLists(node->childAtIndex(i));
+ endIndices[i] = m_transparentNodes.size();
+ }
+
+ Heap<Foo, 16> heap;
+ m_tempNodes.clear();
+ int childNodeCount = m_transparentNodes.size() - baseCount;
+ while (childNodeCount) {
+ for (int i = 0; i < count; ++i) {
+ if (beginIndices[i] != endIndices[i])
+ heap.insert(Foo(i, m_transparentNodes.at(beginIndices[i]++)));
+ }
+ while (!heap.isEmpty()) {
+ Foo foo = heap.pop();
+ m_tempNodes.append(foo.second);
+ --childNodeCount;
+ int i = foo.first;
+ if (beginIndices[i] != endIndices[i] && !nodeLessThan(m_transparentNodes.at(beginIndices[i]), foo.second))
+ heap.insert(Foo(i, m_transparentNodes.at(beginIndices[i]++)));
+ }
+ }
+ Q_ASSERT(m_tempNodes.size() == m_transparentNodes.size() - baseCount);
+
+ m_transparentNodes.resize(baseCount);
+ m_transparentNodes << m_tempNodes;
+ } else {
+ for (int i = 0; i < count; ++i)
+ buildLists(node->childAtIndex(i));
+ }
+}
+
+void QMLRenderer::renderNodes(const QVector<QSGGeometryNode *> &list)
+{
+ const float scale = 1.0f / m_currentRenderOrder;
+ int count = list.count();
+ int currentRenderOrder = 0x80000000;
+
+ //int clipChangeCount = 0;
+ //int programChangeCount = 0;
+ //int materialChangeCount = 0;
+
+ for (int i = 0; i < count; ++i) {
+ QSGGeometryNode *geomNode = list.at(i);
+
+ QSGMaterialShader::RenderState::DirtyStates updates;
+
+#if defined (QML_RUNTIME_TESTING)
+ static bool dumpTree = qApp->arguments().contains(QLatin1String("--dump-tree"));
+ if (dumpTree)
+ qDebug() << geomNode;
+#endif
+
+ bool changeMatrix = m_currentMatrix != geomNode->matrix();
+
+ if (changeMatrix) {
+ m_currentMatrix = geomNode->matrix();
+ if (m_currentMatrix)
+ m_modelViewMatrix = *m_currentMatrix;
+ else
+ m_modelViewMatrix.setToIdentity();
+ updates |= QSGMaterialShader::RenderState::DirtyMatrix;
+ }
+
+ bool changeOpacity = m_render_opacity != geomNode->inheritedOpacity();
+ if (changeOpacity) {
+ updates |= QSGMaterialShader::RenderState::DirtyOpacity;
+ m_render_opacity = geomNode->inheritedOpacity();
+ }
+
+
+ Q_ASSERT(geomNode->activeMaterial());
+
+ QSGMaterial *material = geomNode->activeMaterial();
+ QSGMaterialShader *program = m_context->prepareMaterial(material);
+
+ bool changeClip = geomNode->clipList() != m_currentClip;
+ QSGRenderer::ClipType clipType = QSGRenderer::NoClip;
+ if (changeClip) {
+ clipType = updateStencilClip(geomNode->clipList());
+ m_currentClip = geomNode->clipList();
+#ifdef FORCE_NO_REORDER
+ glDepthMask(false);
+#else
+ glDepthMask((material->flags() & QSGMaterial::Blending) == 0 && m_render_opacity == 1);
+#endif
+ //++clipChangeCount;
+ }
+
+ bool changeProgram = (changeClip && clipType == QSGRenderer::StencilClip) || m_currentProgram != program;
+ if (changeProgram) {
+ if (m_currentProgram)
+ m_currentProgram->deactivate();
+ m_currentProgram = program;
+ m_currentProgram->activate();
+ //++programChangeCount;
+ updates |= (QSGMaterialShader::RenderState::DirtyMatrix | QSGMaterialShader::RenderState::DirtyOpacity);
+ }
+
+ bool changeRenderOrder = currentRenderOrder != geomNode->renderOrder();
+ if (changeRenderOrder) {
+ currentRenderOrder = geomNode->renderOrder();
+ m_renderOrderMatrix(2, 3) = currentRenderOrder * scale;
+ m_projectionMatrix.pop();
+ m_projectionMatrix.push();
+ m_projectionMatrix *= m_renderOrderMatrix;
+ updates |= QSGMaterialShader::RenderState::DirtyMatrix;
+ }
+
+ if (changeProgram || m_currentMaterial != material) {
+ program->updateState(state(updates), material, changeProgram ? 0 : m_currentMaterial);
+ m_currentMaterial = material;
+ //++materialChangeCount;
+ }
+
+ //glDepthRange((geomNode->renderOrder() + 0.1) * scale, (geomNode->renderOrder() + 0.9) * scale);
+
+ const QSGGeometry *g = geomNode->geometry();
+ bindGeometry(program, g);
+ draw(geomNode);
+ }
+ //qDebug("Clip: %i, shader program: %i, material: %i times changed while drawing %s items",
+ // clipChangeCount, programChangeCount, materialChangeCount,
+ // &list == &m_transparentNodes ? "transparent" : "opaque");
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h
new file mode 100644
index 0000000000..805388a06f
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLRENDERER_H
+#define QMLRENDERER_H
+
+#include "qsgrenderer_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QMLRenderer : public QSGRenderer
+{
+ Q_OBJECT
+public:
+ QMLRenderer(QSGContext *context);
+
+ void render();
+
+ void nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags);
+
+ void setSortFrontToBackEnabled(bool sort);
+ bool isSortFrontToBackEnabled() const;
+
+private:
+ void buildLists(QSGNode *node);
+ void renderNodes(const QVector <QSGGeometryNode *> &list);
+
+ const QSGClipNode *m_currentClip;
+ QSGMaterial *m_currentMaterial;
+ QSGMaterialShader *m_currentProgram;
+ const QMatrix4x4 *m_currentMatrix;
+ QMatrix4x4 m_renderOrderMatrix;
+ QVector<QSGGeometryNode *> m_opaqueNodes;
+ QVector<QSGGeometryNode *> m_transparentNodes;
+ QVector<QSGGeometryNode *> m_tempNodes;
+
+ bool m_rebuild_lists;
+ bool m_needs_sorting;
+ bool m_sort_front_to_back;
+ int m_currentRenderOrder;
+
+
+
+#ifdef QML_RUNTIME_TESTING
+ bool m_render_opaque_nodes;
+ bool m_render_alpha_nodes;
+#endif
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLRENDERER_H
diff --git a/src/declarative/scenegraph/coreapi/qsggeometry.cpp b/src/declarative/scenegraph/coreapi/qsggeometry.cpp
new file mode 100644
index 0000000000..1bfffae0bf
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsggeometry.cpp
@@ -0,0 +1,310 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt scene graph research project.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsggeometry.h"
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ Convenience function which returns attributes to be used for 2D solid
+ color drawing.
+ */
+
+const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_Point2D()
+{
+ static Attribute data[] = {
+ { 0, 2, GL_FLOAT }
+ };
+ static AttributeSet attrs = { 1, sizeof(float) * 2, data };
+ return attrs;
+}
+
+/*!
+ Convenience function which returns attributes to be used for textured 2D drawing.
+ */
+
+const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_TexturedPoint2D()
+{
+ static Attribute data[] = {
+ { 0, 2, GL_FLOAT },
+ { 1, 2, GL_FLOAT }
+ };
+ static AttributeSet attrs = { 2, sizeof(float) * 4, data };
+ return attrs;
+}
+
+/*!
+ Convenience function which returns attributes to be used for per vertex colored 2D drawing.
+ */
+
+const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D()
+{
+ static Attribute data[] = {
+ { 0, 2, GL_FLOAT },
+ { 1, 4, GL_UNSIGNED_BYTE }
+ };
+ static AttributeSet attrs = { 2, 2 * sizeof(float) + 4 * sizeof(char), data };
+ return attrs;
+}
+
+
+/*!
+ \class QSGGeometry
+ \brief The QSGGeometry class provides low-level storage for graphics primitives
+ in the QML Scene Graph.
+
+ The QSGGeometry class provides a few convenience attributes and attribute accessors
+ by default. The defaultAttributes_Point2D() function returns attributes to be used
+ in normal solid color rectangles, while the defaultAttributes_TexturedPoint2D function
+ returns attributes to be used for the common pixmap usecase.
+ */
+
+
+/*!
+ Constructs a geometry object based on \a attributes.
+
+ The object allocate space for \a vertexCount vertices based on the accumulated
+ size in \a attributes and for \a indexCount.
+
+ Geometry objects are constructed with GL_TRIANGLE_STRIP as default drawing mode.
+
+ The attribute structure is assumed to be POD and the geometry object
+ assumes this will not go away. There is no memory management involved.
+ */
+
+QSGGeometry::QSGGeometry(const QSGGeometry::AttributeSet &attributes,
+ int vertexCount,
+ int indexCount,
+ int indexType)
+ : m_drawing_mode(GL_TRIANGLE_STRIP)
+ , m_vertex_count(0)
+ , m_index_count(0)
+ , m_index_type(indexType)
+ , m_attributes(attributes)
+ , m_data(0)
+ , m_index_data_offset(-1)
+ , m_owns_data(false)
+{
+ Q_ASSERT(m_attributes.count > 0);
+ Q_ASSERT(m_attributes.stride > 0);
+
+ // Because allocate reads m_vertex_count, m_index_count and m_owns_data, these
+ // need to be set before calling allocate...
+ allocate(vertexCount, indexCount);
+}
+
+QSGGeometry::~QSGGeometry()
+{
+ if (m_owns_data)
+ qFree(m_data);
+}
+
+/*!
+ \fn int QSGGeometry::vertexCount() const
+
+ Returns the number of vertices in this geometry object.
+ */
+
+/*!
+ \fn int QSGGeometry::indexCount() const
+
+ Returns the number of indices in this geometry object.
+ */
+
+
+
+/*!
+ \fn void *QSGGeometry::vertexData()
+
+ Returns a pointer to the raw vertex data of this geometry object.
+
+ \sa vertexDataAsPoint2D(), vertexDataAsTexturedPoint2D
+ */
+
+/*!
+ \fn const void *QSGGeometry::vertexData() const
+
+ Returns a pointer to the raw vertex data of this geometry object.
+
+ \sa vertexDataAsPoint2D(), vertexDataAsTexturedPoint2D
+ */
+
+/*!
+ Returns a pointer to the raw index data of this geometry object.
+
+ \sa indexDataAsUShort(), indexDataAsUInt()
+ */
+void *QSGGeometry::indexData()
+{
+ return m_index_data_offset < 0
+ ? 0
+ : ((char *) m_data + m_index_data_offset);
+}
+
+/*!
+ Returns a pointer to the raw index data of this geometry object.
+
+ \sa indexDataAsUShort(), indexDataAsUInt()
+ */
+const void *QSGGeometry::indexData() const
+{
+ return m_index_data_offset < 0
+ ? 0
+ : ((char *) m_data + m_index_data_offset);
+}
+
+/*!
+ Sets the drawing mode to be used for this geometry.
+
+ The default value is GL_TRIANGLE_STRIP.
+ */
+void QSGGeometry::setDrawingMode(GLenum mode)
+{
+ m_drawing_mode = mode;
+}
+
+/*!
+ \fn int QSGGeometry::drawingMode() const
+
+ Returns the drawing mode of this geometry.
+
+ The default value is GL_TRIANGLE_STRIP.
+ */
+
+/*!
+ \fn int QSGGeometry::indexType() const
+
+ Returns the primitive type used for indices in this
+ geometry object.
+ */
+
+
+/*!
+ Resizes the vertex and index data of this geometry object to fit \a vertexCount
+ vertices and \a indexCount indices.
+
+ Vertex and index data will be invalidated after this call and the caller must
+ */
+void QSGGeometry::allocate(int vertexCount, int indexCount)
+{
+ if (vertexCount == m_vertex_count && indexCount == m_index_count)
+ return;
+
+ m_vertex_count = vertexCount;
+ m_index_count = indexCount;
+
+ bool canUsePrealloc = m_index_count <= 0;
+ int vertexByteSize = m_attributes.stride * m_vertex_count;
+
+ if (m_owns_data)
+ qFree(m_data);
+
+ if (canUsePrealloc && vertexByteSize <= (int) sizeof(m_prealloc)) {
+ m_data = (void *) &m_prealloc[0];
+ m_index_data_offset = -1;
+ m_owns_data = false;
+ } else {
+ Q_ASSERT(m_index_type == GL_UNSIGNED_INT || m_index_type == GL_UNSIGNED_SHORT);
+ int indexByteSize = indexCount * (m_index_type == GL_UNSIGNED_SHORT ? sizeof(quint16) : sizeof(quint32));
+ m_data = (void *) qMalloc(vertexByteSize + indexByteSize);
+ m_index_data_offset = vertexByteSize;
+ m_owns_data = true;
+ }
+
+}
+
+/*!
+ Updates the geometry \a g with the coordinates in \a rect.
+
+ The function assumes the geometry object contains a single triangle strip
+ of QSGGeometry::Point2D vertices
+ */
+void QSGGeometry::updateRectGeometry(QSGGeometry *g, const QRectF &rect)
+{
+ Point2D *v = g->vertexDataAsPoint2D();
+ v[0].x = rect.left();
+ v[0].y = rect.top();
+
+ v[1].x = rect.left();
+ v[1].y = rect.bottom();
+
+ v[2].x = rect.right();
+ v[2].y = rect.top();
+
+ v[3].x = rect.right();
+ v[3].y = rect.bottom();
+}
+
+/*!
+ Updates the geometry \a g with the coordinates in \a rect and texture
+ coordinates from \a textureRect.
+
+ \a textureRect should be in normalized coordinates.
+
+ \a g is assumed to be a triangle strip of four vertices of type
+ QSGGeometry::TexturedPoint2D.
+ */
+void QSGGeometry::updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect, const QRectF &textureRect)
+{
+ TexturedPoint2D *v = g->vertexDataAsTexturedPoint2D();
+ v[0].x = rect.left();
+ v[0].y = rect.top();
+ v[0].tx = textureRect.left();
+ v[0].ty = textureRect.top();
+
+ v[1].x = rect.left();
+ v[1].y = rect.bottom();
+ v[1].tx = textureRect.left();
+ v[1].ty = textureRect.bottom();
+
+ v[2].x = rect.right();
+ v[2].y = rect.top();
+ v[2].tx = textureRect.right();
+ v[2].ty = textureRect.top();
+
+ v[3].x = rect.right();
+ v[3].y = rect.bottom();
+ v[3].tx = textureRect.right();
+ v[3].ty = textureRect.bottom();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsggeometry.h b/src/declarative/scenegraph/coreapi/qsggeometry.h
new file mode 100644
index 0000000000..514fdc466f
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsggeometry.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt scene graph research project.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGGEOMETRY_H
+#define QSGGEOMETRY_H
+
+#include <QtOpenGL/qgl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QSGGeometry
+{
+public:
+ struct Attribute
+ {
+ int position;
+ int tupleSize;
+ int type;
+ };
+
+ struct AttributeSet {
+ int count;
+ int stride;
+ const Attribute *attributes;
+ };
+
+ struct Point2D {
+ float x, y;
+ void set(float nx, float ny) {
+ x = nx; y = ny;
+ }
+ };
+ struct TexturedPoint2D {
+ float x, y;
+ float tx, ty;
+ void set(float nx, float ny, float ntx, float nty) {
+ x = nx; y = ny; tx = ntx; ty = nty;
+ }
+ };
+ struct ColoredPoint2D {
+ float x, y;
+ unsigned char r, g, b, a;
+ void set(float nx, float ny, uchar nr, uchar ng, uchar nb, uchar na) {
+ x = nx; y = ny;
+ r = nr; g = ng, b = nb; a = na;
+ }
+ };
+
+ static const AttributeSet &defaultAttributes_Point2D();
+ static const AttributeSet &defaultAttributes_TexturedPoint2D();
+ static const AttributeSet &defaultAttributes_ColoredPoint2D();
+
+ QSGGeometry(const QSGGeometry::AttributeSet &attribs,
+ int vertexCount,
+ int indexCount = 0,
+ int indexType = GL_UNSIGNED_SHORT);
+ virtual ~QSGGeometry();
+
+ void setDrawingMode(GLenum mode);
+ inline GLenum drawingMode() const { return m_drawing_mode; }
+
+ void allocate(int vertexCount, int indexCount = 0);
+
+ int vertexCount() const { return m_vertex_count; }
+
+ void *vertexData() { return m_data; }
+ inline Point2D *vertexDataAsPoint2D();
+ inline TexturedPoint2D *vertexDataAsTexturedPoint2D();
+ inline ColoredPoint2D *vertexDataAsColoredPoint2D();
+
+ inline const void *vertexData() const { return m_data; }
+ inline const Point2D *vertexDataAsPoint2D() const;
+ inline const TexturedPoint2D *vertexDataAsTexturedPoint2D() const;
+ inline const ColoredPoint2D *vertexDataAsColoredPoint2D() const;
+
+ inline int indexType() const { return m_index_type; }
+
+ int indexCount() const { return m_index_count; }
+
+ void *indexData();
+ inline uint *indexDataAsUInt();
+ inline quint16 *indexDataAsUShort();
+
+ const void *indexData() const;
+ inline const uint *indexDataAsUInt() const;
+ inline const quint16 *indexDataAsUShort() const;
+
+ inline int attributeCount() const { return m_attributes.count; }
+ inline const Attribute *attributes() const { return m_attributes.attributes; }
+ inline int stride() const { return m_attributes.stride; }
+
+ static void updateRectGeometry(QSGGeometry *g, const QRectF &rect);
+ static void updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect, const QRectF &sourceRect);
+
+private:
+ int m_drawing_mode;
+ int m_vertex_count;
+ int m_index_count;
+ int m_index_type;
+ const AttributeSet &m_attributes;
+ void *m_data;
+ int m_index_data_offset;
+
+ void *m_reserved_pointer;
+
+ uint m_owns_data : 1;
+ uint m_reserved_bits : 31;
+
+ float m_prealloc[16];
+};
+
+inline uint *QSGGeometry::indexDataAsUInt()
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_INT);
+ return (uint *) indexData();
+}
+
+inline quint16 *QSGGeometry::indexDataAsUShort()
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_SHORT);
+ return (quint16 *) indexData();
+}
+
+inline const uint *QSGGeometry::indexDataAsUInt() const
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_INT);
+ return (uint *) indexData();
+}
+
+inline const quint16 *QSGGeometry::indexDataAsUShort() const
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_SHORT);
+ return (quint16 *) indexData();
+}
+
+inline QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D()
+{
+ Q_ASSERT(m_attributes.count == 1);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ return (Point2D *) m_data;
+}
+
+inline QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoint2D()
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 4 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_FLOAT);
+ return (TexturedPoint2D *) m_data;
+}
+
+inline QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2D()
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float) + 4 * sizeof(char));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 4);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_UNSIGNED_BYTE);
+ return (ColoredPoint2D *) m_data;
+}
+
+inline const QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D() const
+{
+ Q_ASSERT(m_attributes.count == 1);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ return (const Point2D *) m_data;
+}
+
+inline const QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoint2D() const
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 4 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_FLOAT);
+ return (const TexturedPoint2D *) m_data;
+}
+
+inline const QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2D() const
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float) + 4 * sizeof(char));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 4);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_UNSIGNED_BYTE);
+ return (const ColoredPoint2D *) m_data;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGGEOMETRY_H
diff --git a/src/declarative/scenegraph/coreapi/qsgmaterial.cpp b/src/declarative/scenegraph/coreapi/qsgmaterial.cpp
new file mode 100644
index 0000000000..4c4274419e
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmaterial.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmaterial.h"
+#include "qsgrenderer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGMaterialShader::QSGMaterialShader()
+ : m_compiled(false)
+{
+}
+
+void QSGMaterialShader::activate()
+{
+ if (!m_compiled)
+ compile();
+
+ m_program.bind();
+ char const *const *attr = attributeNames();
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ m_program.enableAttributeArray(i);
+ }
+}
+
+void QSGMaterialShader::deactivate()
+{
+ char const *const *attr = attributeNames();
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ m_program.disableAttributeArray(i);
+ }
+}
+
+void QSGMaterialShader::updateState(const RenderState &, QSGMaterial *, QSGMaterial *)
+{
+}
+
+void QSGMaterialShader::compile()
+{
+ Q_ASSERT(!m_compiled);
+
+ m_program.addShaderFromSourceCode(QGLShader::Vertex, vertexShader());
+ m_program.addShaderFromSourceCode(QGLShader::Fragment, fragmentShader());
+
+ char const *const *attr = attributeNames();
+#ifndef QT_NO_DEBUG
+ int maxVertexAttribs = 0;
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
+ for (int i = 0; attr[i]; ++i) {
+ if (i >= maxVertexAttribs) {
+ qFatal("List of attribute names is either too long or not null-terminated.\n"
+ "Maximum number of attributes on this hardware is %i.\n"
+ "Vertex shader:\n%s\n"
+ "Fragment shader:\n%s\n",
+ maxVertexAttribs, vertexShader(), fragmentShader());
+ }
+ if (*attr[i])
+ m_program.bindAttributeLocation(attr[i], i);
+ }
+#else
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ m_program.bindAttributeLocation(attr[i], i);
+ }
+#endif
+
+ if (!m_program.link()) {
+ qWarning("QSGMaterialShader: Shader compilation failed:");
+ qWarning() << m_program.log();
+ }
+
+ m_compiled = true;
+ initialize();
+}
+
+
+float QSGMaterialShader::RenderState::opacity() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->renderOpacity();
+}
+
+QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->combinedMatrix();
+}
+
+QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const
+{
+ Q_ASSERT(m_data);
+ return const_cast<QSGRenderer *>(static_cast<const QSGRenderer *>(m_data))->modelViewMatrix().top();
+}
+
+QRect QSGMaterialShader::RenderState::viewportRect() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->viewportRect();
+}
+
+QRect QSGMaterialShader::RenderState::deviceRect() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->deviceRect();
+}
+
+const QGLContext *QSGMaterialShader::RenderState::context() const
+{
+ return static_cast<const QSGRenderer *>(m_data)->glContext();
+}
+
+
+#ifndef QT_NO_DEBUG
+static int qt_material_count = 0;
+
+static void qt_print_material_count()
+{
+ qDebug("Number of leaked materials: %i", qt_material_count);
+ qt_material_count = -1;
+}
+#endif
+
+QSGMaterial::QSGMaterial()
+ : m_flags(0)
+{
+#ifndef QT_NO_DEBUG
+ ++qt_material_count;
+ static bool atexit_registered = false;
+ if (!atexit_registered) {
+ atexit(qt_print_material_count);
+ atexit_registered = true;
+ }
+#endif
+}
+
+QSGMaterial::~QSGMaterial()
+{
+#ifndef QT_NO_DEBUG
+ --qt_material_count;
+ if (qt_material_count < 0)
+ qDebug("Material destroyed after qt_print_material_count() was called.");
+#endif
+}
+
+void QSGMaterial::setFlag(Flags flags, bool set)
+{
+ if (set)
+ m_flags |= flags;
+ else
+ m_flags &= ~flags;
+}
+
+int QSGMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ return qint64(this) - qint64(other);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgmaterial.h b/src/declarative/scenegraph/coreapi/qsgmaterial.h
new file mode 100644
index 0000000000..c1513956d0
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmaterial.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MATERIAL_H
+#define MATERIAL_H
+
+#include <qglshaderprogram.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMaterial;
+
+class Q_DECLARATIVE_EXPORT QSGMaterialShader
+{
+public:
+ class Q_DECLARATIVE_EXPORT RenderState {
+ public:
+ enum DirtyState
+ {
+ DirtyMatrix = 0x0001,
+ DirtyOpacity = 0x0002
+ };
+ Q_DECLARE_FLAGS(DirtyStates, DirtyState)
+
+ inline DirtyStates dirtyState() const { return m_dirty; }
+
+ inline bool isMatrixDirty() const { return m_dirty & DirtyMatrix; }
+ inline bool isOpacityDirty() const { return m_dirty & DirtyOpacity; }
+
+ float opacity() const;
+ QMatrix4x4 combinedMatrix() const;
+ QMatrix4x4 modelViewMatrix() const;
+ QRect viewportRect() const;
+ QRect deviceRect() const;
+
+ const QGLContext *context() const;
+
+ private:
+ friend class QSGRenderer;
+ DirtyStates m_dirty;
+ const void *m_data;
+ };
+
+ QSGMaterialShader();
+
+ virtual void activate();
+ virtual void deactivate();
+ // First time a material is used, oldMaterial is null.
+ virtual void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
+ virtual char const *const *attributeNames() const = 0; // Array must end with null.
+
+protected:
+ void compile();
+ virtual void initialize() { }
+
+ virtual const char *vertexShader() const = 0;
+ virtual const char *fragmentShader() const = 0;
+
+ QGLShaderProgram m_program;
+ bool m_compiled;
+ void *m_reserved;
+};
+
+struct QSGMaterialType { };
+
+class Q_DECLARATIVE_EXPORT QSGMaterial
+{
+public:
+ enum Flag {
+ Blending = 0x0001
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QSGMaterial();
+ virtual ~QSGMaterial();
+
+ virtual QSGMaterialType *type() const = 0;
+ virtual QSGMaterialShader *createShader() const = 0;
+ virtual int compare(const QSGMaterial *other) const;
+
+ QSGMaterial::Flags flags() const { return m_flags; }
+
+protected:
+ void setFlag(Flags flags, bool set);
+
+private:
+ Flags m_flags;
+ void *m_reserved;
+ Q_DISABLE_COPY(QSGMaterial)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGMaterial::Flags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGMaterialShader::RenderState::DirtyStates)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp
new file mode 100644
index 0000000000..07ba21d17c
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp
@@ -0,0 +1,380 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmatrix4x4stack.h"
+#include "qsgmatrix4x4stack_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGMatrix4x4Stack
+ \brief The QSGMatrix4x4Stack class manages stacks of transformation matrices in GL applications.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::enablers
+
+ Transformation matrices are one of the basic building blocks of
+ 3D applications, allowing object models to be positioned, scaled,
+ rotated, and projected onto the screen.
+
+ GL systems support several standard kinds of matrices, particularly
+ modelview and projection matrices. These matrices are typically
+ organized into stacks, which allow the current matrix state to be
+ saved with push() and restored later with pop().
+
+ QSGMatrix4x4Stack assists QGLPainter with the management of matrix
+ stacks, providing operations to set and modify transformation
+ matrices in each of the standard matrix stacks.
+
+ In the following example, a standard orthographic projection matrix for a
+ view is set via the QGLPainter::projectionMatrix() stack, and
+ then a modelview matrix is set via the QGLPainter::modelViewMatrix()
+ stack to scale and translate an object prior to drawing:
+
+ \code
+ QGLPainter painter(this);
+
+ QMatrix4x4 projm;
+ projm.ortho(window->rect());
+ painter.projectionMatrix() = projm;
+
+ painter.modelViewMatrix().setToIdentity();
+ painter.modelViewMatrix().translate(-1.0f, 2.0f, 0.0f);
+ painter.modelViewMatrix().scale(0.5f);
+ \endcode
+
+ Later, the application can save the current modelview matrix state
+ and draw a different object with a different modelview matrix:
+
+ \code
+ painter.modelViewMatrix().push();
+ painter.modelViewMatrix().setToIdentity();
+ painter.modelViewMatrix().scale(2.0f);
+ \endcode
+
+ For efficiency, the matrix values are kept client-side until they
+ are needed by a QGLPainter::draw() operation. Until then, changes
+ to the matrix will not be reflected in the GL server. The application
+ can force the GL server to update the server with a call to
+ QGLPainter::update().
+
+ QSGMatrix4x4Stack is supported on all GL platforms, including OpenGL/ES 2.0
+ which doesn't support matrix stacks natively. On that platform, the
+ matrix stack is simulated in client memory. When the application
+ selects a shader program to draw under OpenGL/ES 2.0, it calls
+ top() to obtain the actual value to be set on the shader program.
+
+ \sa QGLPainter
+*/
+
+/*!
+ Creates a matrix stack.
+*/
+QSGMatrix4x4Stack::QSGMatrix4x4Stack()
+ : d_ptr(new QSGMatrix4x4StackPrivate)
+{
+}
+
+/*!
+ Destroy this matrix stack.
+*/
+QSGMatrix4x4Stack::~QSGMatrix4x4Stack()
+{
+}
+
+/*!
+ Pushes the current matrix onto the matrix stack. The matrix can
+ be restored with pop(). The new top of stack will have the
+ same value as the previous top of stack.
+
+ The depths of the traditional \c{GL_MODELVIEW} and \c{GL_PROJECTION}
+ matrix stacks in the GL server are system-dependent and easy to
+ overflow in nested rendering code using \c{glPushMatrix()}.
+ By contrast, the push() function provides an arbitrary-sized stack
+ in client memory.
+
+ \sa pop(), top()
+*/
+void QSGMatrix4x4Stack::push()
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->stack.push(d->matrix);
+}
+
+/*!
+ Pops the top-most matrix from this matrix stack and sets the
+ current matrix to the next value down. Does nothing if the
+ matrix stack contains a single entry.
+
+ \sa push()
+*/
+void QSGMatrix4x4Stack::pop()
+{
+ Q_D(QSGMatrix4x4Stack);
+ if (!d->stack.isEmpty())
+ d->matrix = d->stack.pop();
+ d->isDirty = true;
+}
+
+/*!
+ Set the matrix at the top of this matrix stack to the identity matrix.
+
+ \sa operator=()
+*/
+void QSGMatrix4x4Stack::setToIdentity()
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.setToIdentity();
+ d->isDirty = true;
+}
+
+/*!
+ Returns a const reference to the current matrix at the top of this
+ matrix stack. This is typically used to fetch the matrix so it can
+ be set on user-defined shader programs.
+
+ \sa operator=()
+*/
+const QMatrix4x4 &QSGMatrix4x4Stack::top() const
+{
+ Q_D(const QSGMatrix4x4Stack);
+ return d->matrix;
+}
+
+/*!
+ \fn QSGMatrix4x4Stack::operator const QMatrix4x4 &() const
+
+ Returns a const reference to the current matrix at the top of
+ this matrix stack.
+
+ \sa top()
+*/
+
+/*!
+ Assigns \a matrix to the matrix at the top of this matrix stack.
+
+ \sa top()
+*/
+QSGMatrix4x4Stack& QSGMatrix4x4Stack::operator=(const QMatrix4x4& matrix)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix = matrix;
+ d->isDirty = true;
+ return *this;
+}
+
+/*!
+ Multiplies the matrix at the top of this matrix stack by \a matrix.
+
+ \sa top()
+*/
+QSGMatrix4x4Stack& QSGMatrix4x4Stack::operator*=(const QMatrix4x4& matrix)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix *= matrix;
+ d->isDirty = true;
+ return *this;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that translates coordinates by (\a x, \a y, \a z). The following example
+ translates the modelview matrix by (1, -3, 0):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().translate(1.0f, -3.0f, 0.0f);
+ \endcode
+
+ \sa scale(), rotate()
+*/
+void QSGMatrix4x4Stack::translate(qreal x, qreal y, qreal z)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.translate(x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix statck by another
+ that translates coordinates by the components of \a vector.
+
+ \sa scale(), rotate()
+*/
+void QSGMatrix4x4Stack::translate(const QVector3D& vector)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.translate(vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the components \a x, \a y, and \a z.
+ The following example scales the modelview matrix by (1, 2, 1):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().scale(1.0f, 2.0f, 1.0f);
+ \endcode
+
+ \sa translate(), rotate()
+*/
+void QSGMatrix4x4Stack::scale(qreal x, qreal y, qreal z)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.scale(x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the given \a factor. The following example
+ scales the modelview matrix by a factor of 2:
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().scale(2.0f);
+ \endcode
+
+ \sa translate(), rotate()
+*/
+void QSGMatrix4x4Stack::scale(qreal factor)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.scale(factor);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the components of \a vector.
+
+ \sa translate(), rotate()
+*/
+void QSGMatrix4x4Stack::scale(const QVector3D& vector)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.scale(vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that rotates coordinates through \a angle degrees about the vector
+ (\a x, \a y, \a z). The following example rotates the modelview
+ matrix by 45 degress about the vector (1, -3, 0):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().rotate(45.0f, 1.0f, -3.0f, 0.0f);
+ \endcode
+
+ \sa scale(), translate()
+*/
+void QSGMatrix4x4Stack::rotate(qreal angle, qreal x, qreal y, qreal z)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.rotate(angle, x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that rotates coordinates through \a angle degrees about \a vector.
+
+ \sa scale(), translate()
+*/
+void QSGMatrix4x4Stack::rotate(qreal angle, const QVector3D& vector)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.rotate(angle, vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by the
+ \a quaternion. Thus \c {painter->modelViewMatrix().rotate(quaternion)}
+ is equivalent to the following code:
+ \code
+ QMatrix4x4 mat;
+ mat.rotate(quaternion);
+ painter->modelViewMatrix() *= mat;
+ \endcode
+ which rotates coordinates according to the given \a quaternion.
+
+ \sa scale(), translate()
+*/
+void QSGMatrix4x4Stack::rotate(const QQuaternion &quaternion)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.rotate(quaternion);
+ d->isDirty = true;
+}
+
+/*!
+ Returns true if the top of this matrix stack has been modified;
+ false otherwise.
+
+ \sa setDirty()
+*/
+bool QSGMatrix4x4Stack::isDirty() const
+{
+ Q_D(const QSGMatrix4x4Stack);
+ return d->isDirty;
+}
+
+/*!
+ Sets the \a dirty flag on this matrix stack, which indicates
+ if it has been modified.
+
+ A matrix stack may also be set to dirty by translate(),
+ scale(), operator*(), etc.
+
+ \sa isDirty()
+*/
+void QSGMatrix4x4Stack::setDirty(bool dirty)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->isDirty = dirty;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h
new file mode 100644
index 0000000000..2336598fdc
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGMATRIX4X4STACK_H
+#define QSGMATRIX4X4STACK_H
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMatrix4x4StackPrivate;
+
+class Q_DECLARATIVE_EXPORT QSGMatrix4x4Stack
+{
+public:
+ QSGMatrix4x4Stack();
+ ~QSGMatrix4x4Stack();
+
+ const QMatrix4x4 &top() const;
+
+ void push();
+ void pop();
+
+ void setToIdentity();
+
+ void translate(qreal x, qreal y, qreal z);
+ void translate(const QVector3D& vector);
+ void scale(qreal x, qreal y, qreal z);
+ void scale(qreal factor);
+ void scale(const QVector3D& vector);
+ void rotate(qreal angle, qreal x, qreal y, qreal z);
+ void rotate(qreal angle, const QVector3D& vector);
+ void rotate(const QQuaternion &quaternion);
+
+ QSGMatrix4x4Stack& operator=(const QMatrix4x4& matrix);
+ QSGMatrix4x4Stack& operator*=(const QMatrix4x4& matrix);
+
+ operator const QMatrix4x4 &() const;
+
+ bool isDirty() const;
+ void setDirty(bool dirty);
+
+private:
+ Q_DISABLE_COPY(QSGMatrix4x4Stack)
+ Q_DECLARE_PRIVATE(QSGMatrix4x4Stack)
+
+ QScopedPointer<QSGMatrix4x4StackPrivate> d_ptr;
+
+ friend class QGLPainter;
+};
+
+inline QSGMatrix4x4Stack::operator const QMatrix4x4 &() const
+{
+ return top();
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h
new file mode 100644
index 0000000000..6e5c08ca03
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGMATRIX4X4STACK_P_H
+#define QSGMATRIX4X4STACK_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 <QtGui/qmatrix4x4.h>
+#include <QtCore/qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGMatrix4x4StackPrivate
+{
+public:
+ QSGMatrix4x4StackPrivate() : isDirty(true) {}
+
+ QMatrix4x4 matrix;
+ QStack<QMatrix4x4> stack;
+ bool isDirty;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/scenegraph/coreapi/qsgnode.cpp b/src/declarative/scenegraph/coreapi/qsgnode.cpp
new file mode 100644
index 0000000000..5d84086457
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnode.cpp
@@ -0,0 +1,837 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgnode.h"
+#include "qsgrenderer_p.h"
+#include "qsgnodeupdater_p.h"
+#include "qsgmaterial.h"
+
+#include "limits.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_DEBUG
+static int qt_node_count = 0;
+
+static void qt_print_node_count()
+{
+ qDebug("Number of leaked nodes: %i", qt_node_count);
+ qt_node_count = -1;
+}
+#endif
+
+/*!
+ \class QSGNode
+ \bried The QSGNode class is the base class for all nodes in the scene graph.
+
+ The QSGNode class can be used as a child container. Children are added with
+ the appendChildNode(), prependChildNode(), insertChildNodeBefore() and
+ insertChildNodeAfter(). Ordering is important as nodes are rendered in
+ order. Actually, the scene may reorder nodes freely, but the resulting visual
+ order is still guaranteed.
+
+ If nodes change every frame, the preprocess() function can be used to
+ apply changes to a node for every frame its rendered. The use of preprocess()
+ must be explicitly enabled by setting the QSGNode::UsePreprocess flag
+ on the node.
+
+ The virtual isSubtreeBlocked() function can be used to disable a subtree all
+ together. Nodes in a blocked subtree will not be preprocessed() and not
+ rendered.
+
+ Anything related to QSGNode should happen on the scene graph rendering thread.
+ */
+
+QSGNode::QSGNode()
+ : m_parent(0)
+ , m_nodeFlags(OwnedByParent)
+ , m_flags(0)
+{
+#ifndef QT_NO_DEBUG
+ ++qt_node_count;
+ static bool atexit_registered = false;
+ if (!atexit_registered) {
+ atexit(qt_print_node_count);
+ atexit_registered = true;
+ }
+#endif
+
+}
+
+QSGNode::~QSGNode()
+{
+#ifndef QT_NO_DEBUG
+ --qt_node_count;
+ if (qt_node_count < 0)
+ qDebug("Material destroyed after qt_print_node_count() was called.");
+#endif
+ destroy();
+}
+
+
+/*!
+ \fn void QSGNode::preprocess()
+
+ Override this function to do processing on the node before it is rendered.
+
+ Preprocessing needs to be explicitly enabled by setting the flag
+ QSGNode::UsePreprocess. The flag needs to be set before the node is added
+ to the scene graph and will cause the preprocess() function to be called
+ for every frame the node is rendered.
+
+ The preprocess function is called before the update pass that propegates
+ opacity and transformations through the scene graph. That means that
+ functions like QSGOpacityNode::combinedOpacity() and
+ QSGTransformNode::combinedMatrix() will not contain up-to-date values.
+ If such values are changed during the preprocess, these changes will be
+ propegated through the scene graph before it is rendered.
+
+ \warning Beware of deleting nodes while they are being preprocessed. It is
+ possible, with a small performance hit, to delete a single node during its
+ own preprocess call. Deleting a subtree which has nodes that also use
+ preprocessing may result in a segmentation fault. This is done for
+ performance reasons.
+ */
+
+
+
+
+/*!
+ \fn bool QSGNode::isSubtreeBlocked() const
+
+ Returns whether this node and its subtree is available for use.
+
+ Blocked subtrees will not get their dirty states updated and they
+ will not be rendered.
+
+ The QSGOpacityNode will return a blocked subtree when accumulated opacity
+ is 0, for instance.
+ */
+
+
+void QSGNode::destroy()
+{
+ if (m_parent) {
+ m_parent->removeChildNode(this);
+ Q_ASSERT(m_parent == 0);
+ }
+ for (int ii = m_children.count() - 1; ii >= 0; --ii) {
+ QSGNode *child = m_children.at(ii);
+ removeChildNode(child);
+ Q_ASSERT(child->m_parent == 0);
+ if (child->flags() & OwnedByParent)
+ delete child;
+ }
+ Q_ASSERT(m_children.isEmpty());
+}
+
+void QSGNode::prependChildNode(QSGNode *node)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::prependChildNode", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::prependChildNode", "QSGNode already has a parent");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::prependChildNode", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::prependChildNode", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ m_children.prepend(node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+void QSGNode::appendChildNode(QSGNode *node)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::appendChildNode", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::appendChildNode", "QSGNode already has a parent");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::appendChildNode", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::appendChildNode", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ m_children.append(node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+void QSGNode::insertChildNodeBefore(QSGNode *node, QSGNode *before)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeBefore", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeBefore", "QSGNode already has a parent");
+ Q_ASSERT_X(node->type() != RootNodeType, "QSGNode::insertChildNodeBefore", "RootNodes cannot be children of other nodes");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ int idx = before?m_children.indexOf(before):-1;
+ if (idx == -1)
+ m_children.append(node);
+ else
+ m_children.insert(idx, node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+void QSGNode::insertChildNodeAfter(QSGNode *node, QSGNode *after)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeAfter", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeAfter", "QSGNode already has a parent");
+ Q_ASSERT_X(node->type() != RootNodeType, "QSGNode::insertChildNodeAfter", "RootNodes cannot be children of other nodes");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ int idx = after?m_children.indexOf(after):-1;
+ if (idx == -1)
+ m_children.append(node);
+ else
+ m_children.insert(idx + 1, node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+void QSGNode::removeChildNode(QSGNode *node)
+{
+ Q_ASSERT(m_children.contains(node));
+ Q_ASSERT(node->parent() == this);
+
+ m_children.removeOne(node);
+
+ node->markDirty(DirtyNodeRemoved);
+ node->m_parent = 0;
+}
+
+
+/*!
+ Sets the flag \a f on this node if \a enabled is true;
+ otherwise clears the flag.
+
+ \sa flags()
+*/
+
+void QSGNode::setFlag(Flag f, bool enabled)
+{
+ if (enabled)
+ m_nodeFlags |= f;
+ else
+ m_nodeFlags &= ~f;
+}
+
+
+/*!
+ Sets the flags \a f on this node if \a enabled is true;
+ otherwise clears the flags.
+
+ \sa flags()
+*/
+
+void QSGNode::setFlags(Flags f, bool enabled)
+{
+ if (enabled)
+ m_nodeFlags |= f;
+ else
+ m_nodeFlags &= ~f;
+}
+
+
+void QSGNode::markDirty(DirtyFlags flags)
+{
+ m_flags |= (flags & DirtyPropagationMask);
+
+ DirtyFlags subtreeFlags = DirtyFlags((flags & DirtyPropagationMask) << 16);
+ QSGNode *p = m_parent;
+ while (p) {
+ p->m_flags |= subtreeFlags;
+ if (p->type() == RootNodeType)
+ static_cast<QSGRootNode *>(p)->notifyNodeChange(this, flags);
+ p = p->m_parent;
+ }
+}
+
+QSGBasicGeometryNode::QSGBasicGeometryNode()
+ : m_geometry(0)
+ , m_matrix(0)
+ , m_clip_list(0)
+{
+}
+
+QSGBasicGeometryNode::~QSGBasicGeometryNode()
+{
+ destroy();
+ if (flags() & OwnsGeometry)
+ delete m_geometry;
+}
+
+void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry)
+{
+ if (flags() & OwnsGeometry)
+ delete m_geometry;
+ m_geometry = geometry;
+ markDirty(DirtyGeometry);
+}
+
+
+QSGGeometryNode::QSGGeometryNode()
+ : m_render_order(0)
+ , m_material(0)
+ , m_opaque_material(0)
+ , m_opacity(1)
+{
+}
+
+QSGGeometryNode::~QSGGeometryNode()
+{
+ destroy();
+ if (flags() & OwnsMaterial)
+ delete m_material;
+ if (flags() & OwnsOpaqueMaterial)
+ delete m_opaque_material;
+}
+
+/*!
+ Sets the render order of this node to be \a order.
+
+ GeometryNodes are rendered in an order that visually looks like
+ low order nodes are rendered prior to high order nodes. For opaque
+ geometry there is little difference as z-testing will handle
+ the discard, but for translucent objects, the rendering should
+ normally be specified in the order of back-to-front.
+
+ The default render order is 0.
+
+ \internal
+ */
+void QSGGeometryNode::setRenderOrder(int order)
+{
+ m_render_order = order;
+}
+
+
+
+/*!
+ Sets the material of this geometry node to \a material.
+
+ GeometryNodes must have a material before they can be added to the
+ scene graph.
+ */
+void QSGGeometryNode::setMaterial(QSGMaterial *material)
+{
+ if (flags() & OwnsMaterial)
+ delete m_material;
+ m_material = material;
+#ifndef QT_NO_DEBUG
+ if (m_material != 0 && m_opaque_material == m_material)
+ qWarning("QSGGeometryNode: using same material for both opaque and translucent");
+#endif
+ markDirty(DirtyMaterial);
+}
+
+
+
+/*!
+ Sets the opaque material of this geometry to \a material.
+
+ The opaque material will be preferred by the renderer over the
+ default material, as returned by the material() function, if
+ it is not null and the geometry item has an inherited opacity of
+ 1.
+
+ The opaqueness refers to scene graph opacity, the material is still
+ allowed to set QSGMaterial::Blending to true and draw transparent
+ pixels.
+ */
+void QSGGeometryNode::setOpaqueMaterial(QSGMaterial *material)
+{
+ if (flags() & OwnsOpaqueMaterial)
+ delete m_opaque_material;
+ m_opaque_material = material;
+#ifndef QT_NO_DEBUG
+ if (m_opaque_material != 0 && m_opaque_material == m_material)
+ qWarning("QSGGeometryNode: using same material for both opaque and translucent");
+#endif
+
+ markDirty(DirtyMaterial);
+}
+
+
+
+/*!
+ Returns the material which should currently be used for geometry node.
+
+ If the inherited opacity of the node is 1 and there is an opaque material
+ set on this node, it will be returned; otherwise, the default material
+ will be returned.
+
+ \warning This function requires the scene graph above this item to be
+ completely free of dirty states, so it can only be called during rendering
+
+ \internal
+
+ \sa setMaterial, setOpaqueMaterial
+ */
+QSGMaterial *QSGGeometryNode::activeMaterial() const
+{
+ Q_ASSERT_X(dirtyFlags() == 0, "QSGGeometryNode::activeMaterial()", "function assumes that all dirty states are cleaned up");
+ if (m_opaque_material && m_opacity > 0.999)
+ return m_opaque_material;
+ return m_material;
+}
+
+
+/*!
+ Sets the inherited opacity of this geometry to \a opacity.
+
+ This function is meant to be called by the node preprocessing
+ prior to rendering the tree, so it will not mark the tree as
+ dirty.
+
+ \internal
+ */
+void QSGGeometryNode::setInheritedOpacity(qreal opacity)
+{
+ Q_ASSERT(opacity >= 0 && opacity <= 1);
+ m_opacity = opacity;
+}
+
+
+
+QSGClipNode::QSGClipNode()
+{
+}
+
+QSGClipNode::~QSGClipNode()
+{
+ destroy();
+}
+
+/*!
+ Sets whether this clip node has a rectangular clip to \a rectHint.
+ */
+void QSGClipNode::setIsRectangular(bool rectHint)
+{
+ m_is_rectangular = rectHint;
+}
+
+
+/*!
+ Sets the clip rect of this clip node to \a rect.
+
+ When a rectangular clip is set in combination with setIsRectangular
+ the renderer may in some cases use a more optimal clip method.
+ */
+void QSGClipNode::setClipRect(const QRectF &rect)
+{
+ m_clip_rect = rect;
+}
+
+
+QSGTransformNode::QSGTransformNode()
+{
+}
+
+QSGTransformNode::~QSGTransformNode()
+{
+ destroy();
+}
+
+void QSGTransformNode::setMatrix(const QMatrix4x4 &matrix)
+{
+ m_matrix = matrix;
+ markDirty(DirtyMatrix);
+}
+
+
+/*!
+ Sets the combined matrix of this matrix to \a transform.
+
+ This function is meant to be called by the node preprocessing
+ prior to rendering the tree, so it will not mark the tree as
+ dirty.
+
+ \internal
+ */
+void QSGTransformNode::setCombinedMatrix(const QMatrix4x4 &matrix)
+{
+ m_combined_matrix = matrix;
+}
+
+
+
+QSGRootNode::~QSGRootNode()
+{
+ while (!m_renderers.isEmpty())
+ m_renderers.last()->setRootNode(0);
+ destroy();
+}
+
+
+void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyFlags flags)
+{
+ for (int i=0; i<m_renderers.size(); ++i) {
+ m_renderers.at(i)->nodeChanged(node, flags);
+ }
+}
+
+/*!
+ Constructs an opacity node with a default opacity of 1.
+
+ Opacity accumulate downwards in the scene graph so a node with two
+ QSGOpacityNode instances above it, both with opacity of 0.5, will have
+ effective opacity of 0.25.
+
+ The default opacity of nodes is 1.
+ */
+QSGOpacityNode::QSGOpacityNode()
+ : m_opacity(1)
+ , m_combined_opacity(1)
+{
+}
+
+
+QSGOpacityNode::~QSGOpacityNode()
+{
+ destroy();
+}
+
+
+/*!
+ Sets the opacity of this node to \a opacity.
+
+ Before rendering the graph, the renderer will do an update pass
+ over the subtree to propegate the opacity to its children.
+
+ The value will be bounded to the range 0 to 1.
+ */
+void QSGOpacityNode::setOpacity(qreal opacity)
+{
+ opacity = qBound<qreal>(0, opacity, 1);
+ if (m_opacity == opacity)
+ return;
+ m_opacity = opacity;
+ markDirty(DirtyOpacity);
+}
+
+
+/*!
+ Sets the combined opacity of this node to \a opacity.
+
+ This function is meant to be called by the node preprocessing
+ prior to rendering the tree, so it will not mark the tree as
+ dirty.
+
+ \internal
+ */
+void QSGOpacityNode::setCombinedOpacity(qreal opacity)
+{
+ m_combined_opacity = opacity;
+}
+
+
+bool QSGOpacityNode::isSubtreeBlocked() const
+{
+ return m_combined_opacity < 0.001;
+}
+
+
+QSGNodeVisitor::~QSGNodeVisitor()
+{
+
+}
+
+
+void QSGNodeVisitor::visitNode(QSGNode *n)
+{
+ switch (n->type()) {
+ case QSGNode::TransformNodeType: {
+ QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
+ enterTransformNode(t);
+ visitChildren(t);
+ leaveTransformNode(t);
+ break; }
+ case QSGNode::GeometryNodeType: {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
+ enterGeometryNode(g);
+ visitChildren(g);
+ leaveGeometryNode(g);
+ break; }
+ case QSGNode::ClipNodeType: {
+ QSGClipNode *c = static_cast<QSGClipNode *>(n);
+ enterClipNode(c);
+ visitChildren(c);
+ leaveClipNode(c);
+ break; }
+ case QSGNode::OpacityNodeType: {
+ QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
+ enterOpacityNode(o);
+ visitChildren(o);
+ leaveOpacityNode(o);
+ break; }
+ default:
+ visitChildren(n);
+ break;
+ }
+}
+
+void QSGNodeVisitor::visitChildren(QSGNode *n)
+{
+ int count = n->childCount();
+ for (int i=0; i<count; ++i) {
+ visitNode(n->childAtIndex(i));
+ }
+}
+
+
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const QSGGeometryNode *n)
+{
+ if (!n) {
+ d << "QSGGeometryNode(null)";
+ return d;
+ }
+ d << "QSGGeometryNode(" << hex << (void *) n << dec;
+
+ const QSGGeometry *g = n->geometry();
+
+ if (!g) {
+ d << "no geometry";
+ } else {
+
+ switch (g->drawingMode()) {
+ case GL_TRIANGLE_STRIP: d << "strip"; break;
+ case GL_TRIANGLE_FAN: d << "fan"; break;
+ case GL_TRIANGLES: d << "triangles"; break;
+ default: break;
+ }
+
+ d << g->vertexCount();
+
+ if (g->attributeCount() > 0 && g->attributes()->type == GL_FLOAT) {
+ float x1 = 1e10, x2 = -1e10, y1=1e10, y2=-1e10;
+ int stride = g->stride();
+ for (int i = 0; i < g->vertexCount(); ++i) {
+ float x = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[0];
+ float y = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[1];
+
+ x1 = qMin(x1, x);
+ x2 = qMax(x2, x);
+ y1 = qMin(y1, y);
+ y2 = qMax(y2, y);
+ }
+
+ d << "x1=" << x1 << "y1=" << y1 << "x2=" << x2 << "y2=" << y2;
+ }
+ }
+
+ d << "order=" << n->renderOrder();
+ if (n->material())
+ d << "effect=" << n->material() << "type=" << n->material()->type();
+
+
+ d << ")";
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec;
+ return d;
+}
+
+QDebug operator<<(QDebug d, const QSGClipNode *n)
+{
+ if (!n) {
+ d << "QSGClipNode(null)";
+ return d;
+ }
+ d << "QSGClipNode(" << hex << (void *) n << dec;
+
+ if (n->childCount())
+ d << "children=" << n->childCount();
+
+ d << "is rect?" << (n->isRectangular() ? "yes" : "no");
+
+ d << ")";
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+ return d;
+}
+
+QDebug operator<<(QDebug d, const QSGTransformNode *n)
+{
+ if (!n) {
+ d << "QSGTransformNode(null)";
+ return d;
+ }
+ const QMatrix4x4 m = n->matrix();
+ d << "QSGTransformNode(";
+ d << hex << (void *) n << dec;
+ if (m.isIdentity())
+ d << "identity";
+ else if (m.determinant() == 1 && m(0, 0) == 1 && m(1, 1) == 1 && m(2, 2) == 1)
+ d << "translate" << m(0, 3) << m(1, 3) << m(2, 3);
+ else
+ d << "det=" << n->matrix().determinant();
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+ d << ")";
+ return d;
+}
+
+QDebug operator<<(QDebug d, const QSGOpacityNode *n)
+{
+ if (!n) {
+ d << "QSGOpacityNode(null)";
+ return d;
+ }
+ d << "QSGOpacityNode(";
+ d << hex << (void *) n << dec;
+ d << "opacity=" << n->opacity()
+ << "combined=" << n->combinedOpacity()
+ << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec;
+ d << ")";
+ return d;
+}
+
+
+QDebug operator<<(QDebug d, const QSGRootNode *n)
+{
+ if (!n) {
+ d << "QSGRootNode(null)";
+ return d;
+ }
+ d << "QSGRootNode" << hex << (void *) n << "dirty=" << (int) n->dirtyFlags() << dec
+ << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << ")";
+ return d;
+}
+
+
+
+QDebug operator<<(QDebug d, const QSGNode *n)
+{
+ if (!n) {
+ d << "QSGNode(null)";
+ return d;
+ }
+ switch (n->type()) {
+ case QSGNode::GeometryNodeType:
+ d << static_cast<const QSGGeometryNode *>(n);
+ break;
+ case QSGNode::TransformNodeType:
+ d << static_cast<const QSGTransformNode *>(n);
+ break;
+ case QSGNode::ClipNodeType:
+ d << static_cast<const QSGClipNode *>(n);
+ break;
+ case QSGNode::RootNodeType:
+ d << static_cast<const QSGRootNode *>(n);
+ break;
+ case QSGNode::OpacityNodeType:
+ d << static_cast<const QSGOpacityNode *>(n);
+ break;
+ default:
+ d << "QSGNode(" << hex << (void *) n << dec
+ << "dirty=" << hex << (int) n->dirtyFlags() << dec
+ << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << ")";
+ break;
+ }
+ return d;
+}
+
+void QSGNodeDumper::dump(QSGNode *n)
+{
+ QSGNodeDumper dump;
+ dump.visitNode(n);
+}
+
+void QSGNodeDumper::visitNode(QSGNode *n)
+{
+ if (n->isSubtreeBlocked())
+ return;
+ qDebug() << QString(m_indent * 2, QLatin1Char(' ')) << n;
+ QSGNodeVisitor::visitNode(n);
+}
+
+void QSGNodeDumper::visitChildren(QSGNode *n)
+{
+ ++m_indent;
+ QSGNodeVisitor::visitChildren(n);
+ --m_indent;
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgnode.h b/src/declarative/scenegraph/coreapi/qsgnode.h
new file mode 100644
index 0000000000..fd2bc82b22
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnode.h
@@ -0,0 +1,363 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NODE_H
+#define NODE_H
+
+#include "qsggeometry.h"
+#include <QtGui/QMatrix4x4>
+
+#include <float.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+#define QML_RUNTIME_TESTING
+
+class QSGRenderer;
+
+class QSGNode;
+class QSGRootNode;
+class QSGGeometryNode;
+class QSGTransformNode;
+class QSGClipNode;
+
+class Q_DECLARATIVE_EXPORT QSGNode
+{
+public:
+ enum NodeType {
+ BasicNodeType,
+ RootNodeType,
+ GeometryNodeType,
+ TransformNodeType,
+ ClipNodeType,
+ OpacityNodeType,
+ UserNodeType = 1024
+ };
+
+ enum DirtyFlag {
+ DirtyMatrix = 0x0001,
+ DirtyClipList = 0x0002,
+ DirtyNodeAdded = 0x0004,
+ DirtyNodeRemoved = 0x0008,
+ DirtyGeometry = 0x0010,
+ DirtyRenderOrder = 0x0020,
+ DirtyMaterial = 0x0100,
+ DirtyOpacity = 0x0200,
+ DirtyAll = 0xffff,
+
+ DirtyPropagationMask = DirtyMatrix
+ | DirtyClipList
+ | DirtyNodeAdded
+ | DirtyOpacity,
+
+ };
+ Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
+
+ enum Flag {
+ // Lower 16 bites reserved for general node
+ OwnedByParent = 0x0001,
+ UsePreprocess = 0x0002,
+ ChildrenDoNotOverloap = 0x0004,
+
+ // Upper 16 bits reserved for node subclasses
+
+ // QSGBasicGeometryNode
+ OwnsGeometry = 0x00010000,
+ OwnsMaterial = 0x00020000,
+ OwnsOpaqueMaterial = 0x00040000
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QSGNode();
+ virtual ~QSGNode();
+
+ QSGNode *parent() const { return m_parent; }
+
+ void removeChildNode(QSGNode *node);
+ void prependChildNode(QSGNode *node);
+ void appendChildNode(QSGNode *node);
+ void insertChildNodeBefore(QSGNode *node, QSGNode *before);
+ void insertChildNodeAfter(QSGNode *node, QSGNode *after);
+
+ int childCount() const { return m_children.size(); }
+ QSGNode *childAtIndex(int i) const { return m_children.at(i); }
+
+ virtual NodeType type() const { return BasicNodeType; }
+
+ void clearDirty() { m_flags = 0; }
+ void markDirty(DirtyFlags flags);
+ DirtyFlags dirtyFlags() const { return m_flags; }
+
+ virtual bool isSubtreeBlocked() const { return false; }
+
+ Flags flags() const { return m_nodeFlags; }
+ void setFlag(Flag, bool = true);
+ void setFlags(Flags, bool = true);
+
+ virtual void preprocess() { }
+
+#ifdef QML_RUNTIME_TESTING
+ QString description;
+#endif
+
+protected:
+ // When a node is destroyed, it will detach from the scene graph and the renderer will be
+ // notified about the change. If the node is detached in the base node's destructor, the
+ // renderer can't check what type the node originally was because the node's type() method is
+ // virtual and will return the base node type. The renderer might therefore react incorrectly
+ // to the change. There are a few of ways I can think of to solve the problem:
+ // - The renderer must take into account that the notify method might be called from a node's
+ // destructor.
+ // - The node can have a type property that is set in the constructor.
+ // - All the node destructors must call a common destroy method.
+ // I choose the third option since that will allow the renderer to treat the nodes as their
+ // proper types.
+
+ void destroy();
+
+private:
+ QSGNode *m_parent;
+ QList<QSGNode *> m_children;
+
+ Flags m_nodeFlags;
+ DirtyFlags m_flags;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGNode::DirtyFlags);
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGNode::Flags);
+
+class Q_DECLARATIVE_EXPORT QSGBasicGeometryNode : public QSGNode
+{
+public:
+// enum UsagePattern {
+// Static,
+// Dynamic,
+// Stream
+// };
+// void setUsagePattern(UsagePattern pattern);
+// UsagePattern usagePattern() const { return m_pattern; }
+
+ QSGBasicGeometryNode();
+ ~QSGBasicGeometryNode();
+
+ void setGeometry(QSGGeometry *geometry);
+ const QSGGeometry *geometry() const { return m_geometry; }
+ QSGGeometry *geometry() { return m_geometry; }
+
+ const QMatrix4x4 *matrix() const { return m_matrix; }
+ const QSGClipNode *clipList() const { return m_clip_list; }
+
+private:
+ friend class QSGNodeUpdater;
+ QSGGeometry *m_geometry;
+
+ int m_reserved_start_index;
+ int m_reserved_end_index;
+
+ const QMatrix4x4 *m_matrix;
+ const QSGClipNode *m_clip_list;
+
+// UsagePattern m_pattern;
+};
+
+class QSGMaterial;
+
+class Q_DECLARATIVE_EXPORT QSGGeometryNode : public QSGBasicGeometryNode
+{
+public:
+ QSGGeometryNode();
+ ~QSGGeometryNode();
+
+ void setMaterial(QSGMaterial *material);
+ QSGMaterial *material() const { return m_material; }
+
+ void setOpaqueMaterial(QSGMaterial *material);
+ QSGMaterial *opaqueMaterial() const { return m_opaque_material; }
+
+ QSGMaterial *activeMaterial() const;
+
+ virtual NodeType type() const { return GeometryNodeType; }
+
+ void setRenderOrder(int order);
+ int renderOrder() const { return m_render_order; }
+
+ void setInheritedOpacity(qreal opacity);
+ qreal inheritedOpacity() const { return m_opacity; }
+
+private:
+ friend class QSGNodeUpdater;
+
+ int m_render_order;
+ QSGMaterial *m_material;
+ QSGMaterial *m_opaque_material;
+
+ qreal m_opacity;
+};
+
+class Q_DECLARATIVE_EXPORT QSGClipNode : public QSGBasicGeometryNode
+{
+public:
+ QSGClipNode();
+ ~QSGClipNode();
+
+ virtual NodeType type() const { return ClipNodeType; }
+
+ void setIsRectangular(bool rectHint);
+ bool isRectangular() const { return m_is_rectangular; }
+
+ void setClipRect(const QRectF &);
+ QRectF clipRect() const { return m_clip_rect; }
+
+private:
+ uint m_is_rectangular : 1;
+ uint m_reserved : 31;
+
+ QRectF m_clip_rect;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGTransformNode : public QSGNode
+{
+public:
+ QSGTransformNode();
+ ~QSGTransformNode();
+
+ virtual NodeType type() const { return TransformNodeType; }
+
+ void setMatrix(const QMatrix4x4 &matrix);
+ const QMatrix4x4 &matrix() const { return m_matrix; }
+
+ void setCombinedMatrix(const QMatrix4x4 &matrix);
+ const QMatrix4x4 &combinedMatrix() const { return m_combined_matrix; }
+
+private:
+ QMatrix4x4 m_matrix;
+ QMatrix4x4 m_combined_matrix;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGRootNode : public QSGNode
+{
+public:
+ ~QSGRootNode();
+ NodeType type() const { return RootNodeType; }
+
+private:
+ void notifyNodeChange(QSGNode *node, DirtyFlags flags);
+
+ friend class QSGRenderer;
+ friend class QSGNode;
+ friend class QSGGeometryNode;
+
+ QList<QSGRenderer *> m_renderers;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGOpacityNode : public QSGNode
+{
+public:
+ QSGOpacityNode();
+ ~QSGOpacityNode();
+
+ void setOpacity(qreal opacity);
+ qreal opacity() const { return m_opacity; }
+
+ void setCombinedOpacity(qreal opacity);
+ qreal combinedOpacity() const { return m_combined_opacity; }
+
+ virtual QSGNode::NodeType type() const { return OpacityNodeType; }
+
+ bool isSubtreeBlocked() const;
+
+
+private:
+ qreal m_opacity;
+ qreal m_combined_opacity;
+};
+
+class Q_DECLARATIVE_EXPORT QSGNodeVisitor {
+public:
+ virtual ~QSGNodeVisitor();
+
+protected:
+ virtual void enterTransformNode(QSGTransformNode *) {}
+ virtual void leaveTransformNode(QSGTransformNode *) {}
+ virtual void enterClipNode(QSGClipNode *) {}
+ virtual void leaveClipNode(QSGClipNode *) {}
+ virtual void enterGeometryNode(QSGGeometryNode *) {}
+ virtual void leaveGeometryNode(QSGGeometryNode *) {}
+ virtual void enterOpacityNode(QSGOpacityNode *) {}
+ virtual void leaveOpacityNode(QSGOpacityNode *) {}
+ virtual void visitNode(QSGNode *n);
+ virtual void visitChildren(QSGNode *n);
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGGeometryNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGTransformNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGOpacityNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGRootNode *n);
+
+class QSGNodeDumper : public QSGNodeVisitor {
+
+public:
+ static void dump(QSGNode *n);
+
+ QSGNodeDumper() : m_indent(0) {}
+ void visitNode(QSGNode *n);
+ void visitChildren(QSGNode *n);
+
+private:
+ int m_indent;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // NODE_H
diff --git a/src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp b/src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp
new file mode 100644
index 0000000000..d81248be3d
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgnodeupdater_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// #define QSG_UPDATER_DEBUG
+
+QSGNodeUpdater::QSGNodeUpdater()
+ : m_current_clip(0)
+ , m_force_update(0)
+{
+ m_opacity_stack.push(1);
+}
+
+void QSGNodeUpdater::updateStates(QSGNode *n)
+{
+ m_current_clip = 0;
+ m_force_update = 0;
+
+ Q_ASSERT(m_opacity_stack.size() == 1); // The one we added in the constructr...
+ // Q_ASSERT(m_matrix_stack.isEmpty()); ### no such function?
+ Q_ASSERT(m_combined_matrix_stack.isEmpty());
+
+ visitNode(n);
+}
+
+/*!
+ \fn void QSGNodeUpdater::setToplevelOpacity(qreal opacity)
+
+ Sets the toplevel opacity that will be multiplied with the
+
+ The default opacity is 1. Any other value will cause artifacts, and is
+ primarily useful for debug purposes.
+
+ The changing the value during an update pass will have undefined results
+ */
+
+/*!
+ \fn qreal QSGNodeUpdater::toplevelOpacity() const
+
+ Returns the toplevel opacity for the node updater. The default
+ value is 1.
+ */
+
+
+/*!
+ Returns true if \a node is has something that blocks it in the chain from
+ \a node to \a root doing a full state update pass.
+
+ This function does not process dirty states, simply does a simple traversion
+ up to the top.
+
+ The function assumes that \a root exists in the parent chain of \a node.
+ */
+
+bool QSGNodeUpdater::isNodeBlocked(QSGNode *node, QSGNode *root) const
+{
+ qreal opacity = 1;
+ while (node != root) {
+ if (node->type() == QSGNode::OpacityNodeType) {
+ opacity *= static_cast<QSGOpacityNode *>(node)->opacity();
+ if (opacity < 0.001)
+ return true;
+ }
+ node = node->parent();
+
+ Q_ASSERT_X(node, "QSGNodeUpdater::isNodeBlocked", "node is not in the subtree of root");
+ }
+
+ return false;
+}
+
+
+void QSGNodeUpdater::enterTransformNode(QSGTransformNode *t)
+{
+ if (t->dirtyFlags() & QSGNode::DirtyMatrix)
+ ++m_force_update;
+
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter transform:" << t << "force=" << m_force_update;
+#endif
+
+ if (!t->matrix().isIdentity()) {
+ m_combined_matrix_stack.push(&t->combinedMatrix());
+
+ m_matrix_stack.push();
+ m_matrix_stack *= t->matrix();
+ }
+
+ t->setCombinedMatrix(m_matrix_stack.top());
+}
+
+
+void QSGNodeUpdater::leaveTransformNode(QSGTransformNode *t)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "leave transform:" << t;
+#endif
+
+ if (t->dirtyFlags() & QSGNode::DirtyMatrix)
+ --m_force_update;
+
+ if (!t->matrix().isIdentity()) {
+ m_matrix_stack.pop();
+ m_combined_matrix_stack.pop();
+ }
+
+}
+
+
+void QSGNodeUpdater::enterClipNode(QSGClipNode *c)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter clip:" << c;
+#endif
+
+ if (c->dirtyFlags() & QSGNode::DirtyClipList) {
+ ++m_force_update;
+ }
+
+ c->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.top();
+ c->m_clip_list = m_current_clip;
+ m_current_clip = c;
+}
+
+
+void QSGNodeUpdater::leaveClipNode(QSGClipNode *c)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "leave clip:" << c;
+#endif
+
+ if (c->dirtyFlags() & QSGNode::DirtyClipList) {
+ --m_force_update;
+ }
+
+ m_current_clip = c->m_clip_list;
+}
+
+
+void QSGNodeUpdater::enterGeometryNode(QSGGeometryNode *g)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter geometry:" << g;
+#endif
+
+ g->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.top();
+ g->m_clip_list = m_current_clip;
+ g->setInheritedOpacity(m_opacity_stack.top());
+}
+
+void QSGNodeUpdater::enterOpacityNode(QSGOpacityNode *o)
+{
+ if (o->dirtyFlags() & QSGNode::DirtyOpacity)
+ ++m_force_update;
+
+ qreal opacity = m_opacity_stack.top() * o->opacity();
+ o->setCombinedOpacity(opacity);
+ m_opacity_stack.push(opacity);
+
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter opacity" << o;
+#endif
+}
+
+void QSGNodeUpdater::leaveOpacityNode(QSGOpacityNode *o)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "leave opacity" << o;
+#endif
+ if (o->flags() & QSGNode::DirtyOpacity)
+ --m_force_update;
+
+ m_opacity_stack.pop();
+}
+
+void QSGNodeUpdater::visitChildren(QSGNode *n)
+{
+ if (!n->isSubtreeBlocked())
+ QSGNodeVisitor::visitChildren(n);
+}
+
+void QSGNodeUpdater::visitNode(QSGNode *n)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter:" << n;
+#endif
+
+ if (n->dirtyFlags() || m_force_update) {
+ bool forceUpdate = n->dirtyFlags() & (QSGNode::DirtyNodeAdded);
+ if (forceUpdate)
+ ++m_force_update;
+
+ QSGNodeVisitor::visitNode(n);
+
+ if (forceUpdate)
+ --m_force_update;
+
+ n->clearDirty();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h b/src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h
new file mode 100644
index 0000000000..518cf9eff9
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NODEUPDATER_P_H
+#define NODEUPDATER_P_H
+
+#include "qsgnode.h"
+#include "qsgmatrix4x4stack.h"
+#include <qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_DECLARATIVE_EXPORT QSGNodeUpdater : public QSGNodeVisitor
+{
+public:
+ QSGNodeUpdater();
+
+ virtual void updateStates(QSGNode *n);
+ virtual bool isNodeBlocked(QSGNode *n, QSGNode *root) const;
+
+ void setToplevelOpacity(qreal alpha) { m_opacity_stack.top() = alpha; }
+ qreal toplevelOpacity() const { return m_opacity_stack.top(); }
+
+protected:
+ void enterTransformNode(QSGTransformNode *);
+ void leaveTransformNode(QSGTransformNode *);
+ void enterClipNode(QSGClipNode *c);
+ void leaveClipNode(QSGClipNode *c);
+ void enterOpacityNode(QSGOpacityNode *o);
+ void leaveOpacityNode(QSGOpacityNode *o);
+ void enterGeometryNode(QSGGeometryNode *);
+
+ void visitNode(QSGNode *n);
+ void visitChildren(QSGNode *n);
+
+
+ QSGMatrix4x4Stack m_matrix_stack;
+ QStack<const QMatrix4x4 *> m_combined_matrix_stack;
+ QStack<qreal> m_opacity_stack;
+ const QSGClipNode *m_current_clip;
+
+ int m_force_update;
+
+ qreal m_toplevel_alpha;
+};
+
+QT_END_NAMESPACE
+
+#endif // NODEUPDATER_P_H
diff --git a/src/declarative/scenegraph/coreapi/qsgrenderer.cpp b/src/declarative/scenegraph/coreapi/qsgrenderer.cpp
new file mode 100644
index 0000000000..eb7b830ade
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgrenderer.cpp
@@ -0,0 +1,545 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrenderer_p.h"
+#include "qsgnode.h"
+#include "qsgmaterial.h"
+#include "qsgnodeupdater_p.h"
+
+#include "private/qsgadaptationlayer_p.h"
+
+#include <QGLShaderProgram>
+#include <qglframebufferobject.h>
+#include <QtGui/qapplication.h>
+
+#include <qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define RENDERER_DEBUG
+//#define QT_GL_NO_SCISSOR_TEST
+
+// #define QSG_RENDERER_TIMING
+#ifdef QSG_RENDERER_TIMING
+static QTime frameTimer;
+static int preprocessTime;
+static int updatePassTime;
+static int frameNumber = 0;
+#endif
+
+void Bindable::clear(QSGRenderer::ClearMode mode) const
+{
+ GLuint bits = 0;
+ if (mode & QSGRenderer::ClearColorBuffer) bits |= GL_COLOR_BUFFER_BIT;
+ if (mode & QSGRenderer::ClearDepthBuffer) bits |= GL_DEPTH_BUFFER_BIT;
+ if (mode & QSGRenderer::ClearStencilBuffer) bits |= GL_STENCIL_BUFFER_BIT;
+ glClear(bits);
+}
+
+// Reactivate the color buffer after switching to the stencil.
+void Bindable::reactivate() const
+{
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+}
+
+BindableFbo::BindableFbo(QGLFramebufferObject *fbo) : m_fbo(fbo)
+{
+}
+
+
+void BindableFbo::bind() const
+{
+ m_fbo->bind();
+}
+
+/*!
+ \class QSGRenderer
+ \brief The renderer class is the abstract baseclass use for rendering the
+ QML scene graph.
+
+ The renderer is not tied to any particular surface. It expects a context to
+ be current and will render into that surface according to how the device rect,
+ viewport rect and projection transformation are set up.
+
+ Rendering is a sequence of steps initiated by calling renderScene(). This will
+ effectively draw the scene graph starting at the root node. The QSGNode::preprocess()
+ function will be called for all the nodes in the graph, followed by an update
+ pass which updates all matrices, opacity, clip states and similar in the graph.
+ Because the update pass is called after preprocess, it is safe to modify the graph
+ during preprocess. To run a custom update pass over the graph, install a custom
+ QSGNodeUpdater using setNodeUpdater(). Once all the graphs dirty states are updated,
+ the virtual render() function is called.
+
+ The render() function is implemented by QSGRenderer subclasses to render the graph
+ in the most optimal way for a given hardware.
+
+ The renderer can make use of stencil, depth and color buffers in addition to the
+ scissor rect.
+
+ \internal
+ */
+
+
+QSGRenderer::QSGRenderer(QSGContext *context)
+ : QObject()
+ , m_clear_color(Qt::transparent)
+ , m_clear_mode(ClearColorBuffer | ClearDepthBuffer)
+ , m_render_opacity(1)
+ , m_context(context)
+ , m_root_node(0)
+ , m_node_updater(0)
+ , m_changed_emitted(false)
+ , m_mirrored(false)
+ , m_is_rendering(false)
+ , m_bindable(0)
+{
+ initializeGLFunctions();
+}
+
+
+QSGRenderer::~QSGRenderer()
+{
+ setRootNode(0);
+ delete m_node_updater;
+}
+
+/*!
+ Returns the scene graph context for this renderer.
+
+ \internal
+ */
+
+QSGContext *QSGRenderer::context()
+{
+ return m_context;
+}
+
+
+
+
+/*!
+ Returns the node updater that this renderer uses to update states in the
+ scene graph.
+
+ If no updater is specified a default one is constructed.
+ */
+
+QSGNodeUpdater *QSGRenderer::nodeUpdater() const
+{
+ if (!m_node_updater)
+ const_cast<QSGRenderer *>(this)->m_node_updater = new QSGNodeUpdater();
+ return m_node_updater;
+}
+
+
+/*!
+ Sets the node updater that this renderer uses to update states in the
+ scene graph.
+
+ This will delete and override any existing node updater
+ */
+void QSGRenderer::setNodeUpdater(QSGNodeUpdater *updater)
+{
+ if (m_node_updater)
+ delete m_node_updater;
+ m_node_updater = updater;
+}
+
+
+void QSGRenderer::setRootNode(QSGRootNode *node)
+{
+ if (m_root_node == node)
+ return;
+ if (m_root_node) {
+ m_root_node->m_renderers.removeOne(this);
+ nodeChanged(m_root_node, QSGNode::DirtyNodeRemoved);
+ }
+ m_root_node = node;
+ if (m_root_node) {
+ Q_ASSERT(!m_root_node->m_renderers.contains(this));
+ m_root_node->m_renderers << this;
+ nodeChanged(m_root_node, QSGNode::DirtyNodeAdded);
+ }
+}
+
+
+void QSGRenderer::renderScene()
+{
+ class B : public Bindable
+ {
+ public:
+ B() : m_ctx(const_cast<QGLContext *>(QGLContext::currentContext())) { }
+ void bind() const { QGLFramebufferObject::bindDefault(); }
+ private:
+ QGLContext *m_ctx;
+ } b;
+ renderScene(b);
+}
+
+void QSGRenderer::renderScene(const Bindable &bindable)
+{
+ if (!m_root_node)
+ return;
+
+ m_is_rendering = true;
+#ifdef QSG_RENDERER_TIMING
+ frameTimer.start();
+#endif
+
+ m_bindable = &bindable;
+ preprocess();
+
+ bindable.bind();
+#ifdef QSG_RENDERER_TIMING
+ int bindTime = frameTimer.elapsed();
+#endif
+
+ render();
+#ifdef QSG_RENDERER_TIMING
+ int renderTime = frameTimer.elapsed();
+#endif
+
+ glDisable(GL_SCISSOR_TEST);
+ m_is_rendering = false;
+ m_changed_emitted = false;
+ m_bindable = 0;
+
+#ifdef QSG_RENDERER_TIMING
+ printf("Frame #%d: Breakdown of frametime: preprocess=%d, updates=%d, binding=%d, render=%d, total=%d\n",
+ ++frameNumber,
+ preprocessTime,
+ updatePassTime - preprocessTime,
+ bindTime - updatePassTime,
+ renderTime - bindTime,
+ renderTime);
+#endif
+}
+
+void QSGRenderer::setProjectMatrixToDeviceRect()
+{
+ setProjectMatrixToRect(m_device_rect);
+}
+
+void QSGRenderer::setProjectMatrixToRect(const QRectF &rect)
+{
+ QMatrix4x4 matrix;
+ matrix.ortho(rect.x(),
+ rect.x() + rect.width(),
+ rect.y() + rect.height(),
+ rect.y(),
+ qreal(0.01),
+ -1);
+ setProjectMatrix(matrix);
+}
+
+void QSGRenderer::setProjectMatrix(const QMatrix4x4 &matrix)
+{
+ m_projection_matrix = matrix;
+ // Mirrored relative to the usual Qt coordinate system with origin in the top left corner.
+ m_mirrored = matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
+}
+
+void QSGRenderer::setClearColor(const QColor &color)
+{
+ m_clear_color = color;
+}
+
+void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags)
+{
+ Q_UNUSED(node);
+ Q_UNUSED(flags);
+
+ if (flags & QSGNode::DirtyNodeAdded)
+ addNodesToPreprocess(node);
+ if (flags & QSGNode::DirtyNodeRemoved)
+ removeNodesToPreprocess(node);
+
+ if (!m_changed_emitted && !m_is_rendering) {
+ // Premature overoptimization to avoid excessive signal emissions
+ m_changed_emitted = true;
+ emit sceneGraphChanged();
+ }
+}
+
+void QSGRenderer::materialChanged(QSGGeometryNode *, QSGMaterial *, QSGMaterial *)
+{
+}
+
+void QSGRenderer::preprocess()
+{
+ Q_ASSERT(m_root_node);
+
+ // We need to take a copy here, in case any of the preprocess calls deletes a node that
+ // is in the preprocess list and thus, changes the m_nodes_to_preprocess behind our backs
+ // For the default case, when this does not happen, the cost is neglishible.
+ QSet<QSGNode *> items = m_nodes_to_preprocess;
+
+ for (QSet<QSGNode *>::const_iterator it = items.constBegin();
+ it != items.constEnd(); ++it) {
+ QSGNode *n = *it;
+ if (!nodeUpdater()->isNodeBlocked(n, m_root_node)) {
+ n->preprocess();
+ }
+ }
+
+#ifdef QSG_RENDERER_TIMING
+ preprocessTime = frameTimer.elapsed();
+#endif
+
+ nodeUpdater()->setToplevelOpacity(context()->renderAlpha());
+ nodeUpdater()->updateStates(m_root_node);
+
+#ifdef QSG_RENDERER_TIMING
+ updatePassTime = frameTimer.elapsed();
+#endif
+
+}
+
+void QSGRenderer::addNodesToPreprocess(QSGNode *node)
+{
+ for (int i = 0; i < node->childCount(); ++i)
+ addNodesToPreprocess(node->childAtIndex(i));
+ if (node->flags() & QSGNode::UsePreprocess)
+ m_nodes_to_preprocess.insert(node);
+}
+
+void QSGRenderer::removeNodesToPreprocess(QSGNode *node)
+{
+ for (int i = 0; i < node->childCount(); ++i)
+ removeNodesToPreprocess(node->childAtIndex(i));
+ if (node->flags() & QSGNode::UsePreprocess)
+ m_nodes_to_preprocess.remove(node);
+}
+
+
+/*!
+ Convenience function to set up the stencil buffer for clipping based on \a clip.
+
+ If the clip is a pixel aligned rectangle, this function will use glScissor instead
+ of stencil.
+ */
+
+QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip)
+{
+ if (!clip) {
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ return NoClip;
+ }
+
+ bool stencilEnabled = false;
+ bool scissorEnabled = false;
+
+ glDisable(GL_SCISSOR_TEST);
+
+ int clipDepth = 0;
+ QRect clipRect;
+ while (clip) {
+ QMatrix4x4 matrix = m_projectionMatrix.top();
+ if (clip->matrix())
+ matrix *= *clip->matrix();
+
+ const QMatrix4x4 &m = matrix;
+
+ // TODO: Check for multisampling and pixel grid alignment.
+ bool canUseScissor = clip->isRectangular()
+ && qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(0, 2))
+ && qFuzzyIsNull(m(1, 0)) && qFuzzyIsNull(m(1, 2));
+
+ if (canUseScissor) {
+ QRectF bbox = clip->clipRect();
+ qreal invW = 1 / m(3, 3);
+ qreal fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW;
+ qreal fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW;
+ qreal fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW;
+ qreal fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW;
+
+ GLint ix1 = qRound((fx1 + 1) * m_device_rect.width() * qreal(0.5));
+ GLint iy1 = qRound((fy1 + 1) * m_device_rect.height() * qreal(0.5));
+ GLint ix2 = qRound((fx2 + 1) * m_device_rect.width() * qreal(0.5));
+ GLint iy2 = qRound((fy2 + 1) * m_device_rect.height() * qreal(0.5));
+
+ if (!scissorEnabled) {
+ clipRect = QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
+ glEnable(GL_SCISSOR_TEST);
+ scissorEnabled = true;
+ } else {
+ clipRect &= QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
+ }
+
+ clipRect = clipRect.normalized();
+ glScissor(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
+ } else {
+ if (!stencilEnabled) {
+ if (!m_clip_program.isLinked()) {
+ m_clip_program.addShaderFromSourceCode(QGLShader::Vertex,
+ "attribute highp vec4 vCoord; \n"
+ "uniform highp mat4 matrix; \n"
+ "void main() { \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}");
+ m_clip_program.addShaderFromSourceCode(QGLShader::Fragment,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); \n" // Trolltech green ftw!
+ "}");
+ m_clip_program.bindAttributeLocation("vCoord", 0);
+ m_clip_program.link();
+ m_clip_matrix_id = m_clip_program.uniformLocation("matrix");
+ }
+
+ glStencilMask(0xff); // write mask
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glEnable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ glDepthMask(GL_FALSE);
+
+ m_clip_program.bind();
+ m_clip_program.enableAttributeArray(0);
+
+ stencilEnabled = true;
+ }
+
+ glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // stencil fail, z fail, z pass
+
+ const QSGGeometry *geometry = clip->geometry();
+ Q_ASSERT(geometry->attributeCount() > 0);
+ const QSGGeometry::Attribute *a = geometry->attributes();
+
+ glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, geometry->stride(), geometry->vertexData());
+
+ m_clip_program.setUniformValue(m_clip_matrix_id, m);
+ draw(clip);
+
+ ++clipDepth;
+ }
+
+ clip = clip->clipList();
+ }
+
+ if (stencilEnabled) {
+ m_clip_program.disableAttributeArray(0);
+ glEnable(GL_DEPTH_TEST);
+ glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // stencil fail, z fail, z pass
+ glStencilMask(0); // write mask
+ bindable()->reactivate();
+ //glDepthMask(GL_TRUE); // must be reset correctly by caller.
+ } else {
+ glDisable(GL_STENCIL_TEST);
+ }
+
+ if (!scissorEnabled)
+ glDisable(GL_SCISSOR_TEST);
+
+ return stencilEnabled ? StencilClip : ScissorClip;
+}
+
+
+/*!
+ Issues the GL draw call for \a geometryNode.
+
+ The function assumes that attributes have been bound and set up prior
+ to making this call.
+
+ \internal
+ */
+
+void QSGRenderer::draw(const QSGBasicGeometryNode *node)
+{
+ const QSGGeometry *g = node->geometry();
+ if (g->indexCount()) {
+ glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
+ } else {
+ glDrawArrays(g->drawingMode(), 0, g->vertexCount());
+ }
+}
+
+
+static inline int size_of_type(GLenum type)
+{
+ static int sizes[] = {
+ sizeof(char),
+ sizeof(unsigned char),
+ sizeof(short),
+ sizeof(unsigned short),
+ sizeof(int),
+ sizeof(unsigned int),
+ sizeof(float),
+ 2,
+ 3,
+ 4,
+ sizeof(double)
+ };
+ return sizes[type - GL_BYTE];
+}
+
+/*!
+ Convenience function to set up and bind the vertex data in \a g to the
+ required attribute positions defined in \a material.
+
+ \internal
+ */
+
+void QSGRenderer::bindGeometry(QSGMaterialShader *material, const QSGGeometry *g)
+{
+ char const *const *attrNames = material->attributeNames();
+ int offset = 0;
+ for (int j = 0; attrNames[j]; ++j) {
+ if (!*attrNames[j])
+ continue;
+ Q_ASSERT_X(j < g->attributeCount(), "QSGRenderer::bindGeometry()", "Geometry lacks attribute required by material");
+ const QSGGeometry::Attribute &a = g->attributes()[j];
+ Q_ASSERT_X(j == a.position, "QSGRenderer::bindGeometry()", "Geometry does not have continuous attribute positions");
+#if defined(QT_OPENGL_ES_2)
+ GLboolean normalize = a.type != GL_FLOAT;
+#else
+ GLboolean normalize = a.type != GL_FLOAT && a.type != GL_DOUBLE;
+#endif
+ glVertexAttribPointer(a.position, a.tupleSize, a.type, normalize, g->stride(), (char *) g->vertexData() + offset);
+ offset += a.tupleSize * size_of_type(a.type);
+ }
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgrenderer_p.h b/src/declarative/scenegraph/coreapi/qsgrenderer_p.h
new file mode 100644
index 0000000000..fcf966d819
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgrenderer_p.h
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include <qset.h>
+#include <qhash.h>
+
+#include "qsgmatrix4x4stack.h"
+
+#include <qglfunctions.h>
+#include <qglshaderprogram.h>
+
+#include "qsgnode.h"
+#include "qsgmaterial.h"
+#include "qsgtexture.h"
+
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMaterialShader;
+struct QSGMaterialType;
+class QGLFramebufferObject;
+class TextureReference;
+class Bindable;
+class QSGNodeUpdater;
+
+
+class Q_DECLARATIVE_EXPORT QSGRenderer : public QObject, public QGLFunctions
+{
+ Q_OBJECT
+public:
+ enum ClipType
+ {
+ NoClip,
+ ScissorClip,
+ StencilClip
+ };
+
+ enum ClearModeBit
+ {
+ ClearColorBuffer = 0x0001,
+ ClearDepthBuffer = 0x0002,
+ ClearStencilBuffer = 0x0004
+ };
+ Q_DECLARE_FLAGS(ClearMode, ClearModeBit)
+
+ QSGRenderer(QSGContext *context);
+ virtual ~QSGRenderer();
+
+ void setRootNode(QSGRootNode *node);
+ QSGRootNode *rootNode() const { return m_root_node; }
+
+ void setDeviceRect(const QRect &rect) { m_device_rect = rect; }
+ inline void setDeviceRect(const QSize &size) { setDeviceRect(QRect(QPoint(), size)); }
+ QRect deviceRect() const { return m_device_rect; }
+
+ void setViewportRect(const QRect &rect) { m_viewport_rect = rect; }
+ inline void setViewportRect(const QSize &size) { setViewportRect(QRect(QPoint(), size)); }
+ QRect viewportRect() const { return m_viewport_rect; }
+
+ QSGMatrix4x4Stack &projectionMatrix() { return m_projectionMatrix; }
+ QSGMatrix4x4Stack &modelViewMatrix() { return m_modelViewMatrix; }
+ QMatrix4x4 combinedMatrix() const { return m_projectionMatrix.top() * m_modelViewMatrix.top(); }
+
+ void setProjectMatrixToDeviceRect();
+ void setProjectMatrixToRect(const QRectF &rect);
+ void setProjectMatrix(const QMatrix4x4 &matrix);
+ QMatrix4x4 projectMatrix() const { return m_projection_matrix; }
+ bool isMirrored() const { return m_mirrored; }
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+ void setClearColor(const QColor &color);
+ QColor clearColor() const { return m_clear_color; }
+
+ const QGLContext *glContext() const { Q_ASSERT(m_context); return m_context->glContext(); }
+
+ QSGContext *context();
+
+ void renderScene();
+ void renderScene(const Bindable &bindable);
+ virtual void nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags);
+ virtual void materialChanged(QSGGeometryNode *node, QSGMaterial *from, QSGMaterial *to);
+
+ QSGNodeUpdater *nodeUpdater() const;
+ void setNodeUpdater(QSGNodeUpdater *updater);
+
+ inline QSGMaterialShader::RenderState state(QSGMaterialShader::RenderState::DirtyStates dirty) const;
+
+ void setClearMode(ClearMode mode) { m_clear_mode = mode; }
+ ClearMode clearMode() const { return m_clear_mode; }
+
+signals:
+ void sceneGraphChanged(); // Add, remove, ChangeFlags changes...
+
+protected:
+ void draw(const QSGBasicGeometryNode *geometry);
+ void bindGeometry(QSGMaterialShader *material, const QSGGeometry *g);
+
+ virtual void render() = 0;
+ QSGRenderer::ClipType updateStencilClip(const QSGClipNode *clip);
+
+ const Bindable *bindable() const { return m_bindable; }
+
+ virtual void preprocess();
+
+ void addNodesToPreprocess(QSGNode *node);
+ void removeNodesToPreprocess(QSGNode *node);
+
+
+ QColor m_clear_color;
+ ClearMode m_clear_mode;
+ QSGMatrix4x4Stack m_projectionMatrix;
+ QSGMatrix4x4Stack m_modelViewMatrix;
+ qreal m_render_opacity;
+
+ QSGContext *m_context;
+
+private:
+ QSGRootNode *m_root_node;
+ QSGNodeUpdater *m_node_updater;
+
+ QRect m_device_rect;
+ QRect m_viewport_rect;
+
+ QSet<QSGNode *> m_nodes_to_preprocess;
+
+ QMatrix4x4 m_projection_matrix;
+ QGLShaderProgram m_clip_program;
+ int m_clip_matrix_id;
+
+ bool m_changed_emitted;
+ bool m_mirrored;
+ bool m_is_rendering;
+
+ const Bindable *m_bindable;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderer::ClearMode)
+
+class Q_DECLARATIVE_EXPORT Bindable
+{
+public:
+ virtual ~Bindable() { }
+ virtual void bind() const = 0;
+ virtual void clear(QSGRenderer::ClearMode mode) const;
+ virtual void reactivate() const;
+};
+
+class BindableFbo : public Bindable
+{
+public:
+ BindableFbo(QGLFramebufferObject *fbo);
+ virtual void bind() const;
+private:
+ QGLFramebufferObject *m_fbo;
+};
+
+
+
+QSGMaterialShader::RenderState QSGRenderer::state(QSGMaterialShader::RenderState::DirtyStates dirty) const
+{
+ QSGMaterialShader::RenderState s;
+ s.m_dirty = dirty;
+ s.m_data = this;
+ return s;
+}
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // RENDERER_H
diff --git a/src/declarative/scenegraph/qsgadaptationlayer.cpp b/src/declarative/scenegraph/qsgadaptationlayer.cpp
new file mode 100644
index 0000000000..81fac6a1a8
--- /dev/null
+++ b/src/declarative/scenegraph/qsgadaptationlayer.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgadaptationlayer_p.h"
diff --git a/src/declarative/scenegraph/qsgadaptationlayer_p.h b/src/declarative/scenegraph/qsgadaptationlayer_p.h
new file mode 100644
index 0000000000..1e7c794ea9
--- /dev/null
+++ b/src/declarative/scenegraph/qsgadaptationlayer_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ADAPTATIONINTERFACES_H
+#define ADAPTATIONINTERFACES_H
+
+#include "qsgnode.h"
+#include "qsgtexture.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qcolor.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtGui/qglyphs.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGNode;
+class QImage;
+class TextureReference;
+
+// TODO: Rename from XInterface to AbstractX.
+class Q_DECLARATIVE_EXPORT QSGRectangleNode : public QSGGeometryNode
+{
+public:
+ virtual void setRect(const QRectF &rect) = 0;
+ virtual void setColor(const QColor &color) = 0;
+ virtual void setPenColor(const QColor &color) = 0;
+ virtual void setPenWidth(qreal width) = 0;
+ virtual void setGradientStops(const QGradientStops &stops) = 0;
+ virtual void setRadius(qreal radius) = 0;
+
+ virtual void update() = 0;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGImageNode : public QSGGeometryNode
+{
+public:
+ virtual void setTargetRect(const QRectF &rect) = 0;
+ virtual void setSourceRect(const QRectF &rect) = 0;
+ virtual void setTexture(QSGTexture *texture) = 0;
+
+ virtual void setMipmapFiltering(QSGTexture::Filtering filtering) = 0;
+ virtual void setFiltering(QSGTexture::Filtering filtering) = 0;
+ virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) = 0;
+ virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode) = 0;
+
+ virtual void update() = 0;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGGlyphNode : public QSGGeometryNode
+{
+public:
+ enum AntialiasingMode
+ {
+ GrayAntialiasing,
+ SubPixelAntialiasing
+ };
+
+ virtual void setGlyphs(const QPointF &position, const QGlyphs &glyphs) = 0;
+ virtual void setColor(const QColor &color) = 0;
+ virtual QPointF baseLine() const = 0;
+
+ virtual QRectF boundingRect() const { return m_bounding_rect; }
+ virtual void setBoundingRect(const QRectF &bounds) { m_bounding_rect = bounds; }
+
+ virtual void setPreferredAntialiasingMode(AntialiasingMode) = 0;
+
+protected:
+ QRectF m_bounding_rect;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/qsgcontext.cpp b/src/declarative/scenegraph/qsgcontext.cpp
new file mode 100644
index 0000000000..2a43d03028
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontext.cpp
@@ -0,0 +1,428 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgrenderer_p.h>
+#include "qsgnode.h"
+
+#include <private/qsgdefaultrenderer_p.h>
+
+#include <private/qsgdefaultrectanglenode_p.h>
+#include <private/qsgdefaultimagenode_p.h>
+#include <private/qsgdefaultglyphnode_p.h>
+#include <private/qsgdistancefieldglyphnode_p.h>
+#include <private/qsgdistancefieldglyphcache_p.h>
+
+#include <private/qsgtexture_p.h>
+#include <qsgengine.h>
+
+#include <QApplication>
+#include <QGLContext>
+
+#include <private/qobject_p.h>
+#include <qmutex.h>
+
+DEFINE_BOOL_CONFIG_OPTION(qmlFlashMode, QML_FLASH_MODE)
+DEFINE_BOOL_CONFIG_OPTION(qmlTranslucentMode, QML_TRANSLUCENT_MODE)
+
+/*!
+ Comments about this class from Gunnar:
+
+ The QSGContext class is right now two things.. The first is the
+ adaptation layer and central storage ground for all the things
+ in the scene graph, like textures and materials. This part really
+ belongs inside the scene graph coreapi.
+
+ The other part is the QML adaptation classes, like how to implement
+ rectangle nodes. This is not part of the scene graph core API, but
+ more part of the QML adaptation of scene graph.
+
+ If we ever move the scene graph core API into its own thing, this class
+ needs to be split in two. Right now its one because we're lazy when it comes
+ to defining plugin interfaces..
+
+ */
+
+
+QT_BEGIN_NAMESPACE
+
+class QSGContextPrivate : public QObjectPrivate
+{
+public:
+ QSGContextPrivate()
+ : rootNode(0)
+ , renderer(0)
+ , gl(0)
+ , flashMode(qmlFlashMode())
+ {
+ renderAlpha = qmlTranslucentMode() ? 0.5 : 1;
+ }
+
+ ~QSGContextPrivate()
+ {
+ }
+
+ QSGRootNode *rootNode;
+ QSGRenderer *renderer;
+
+ QGLContext *gl;
+
+ QSGEngine engine;
+
+ QHash<QSGMaterialType *, QSGMaterialShader *> materials;
+
+ QMutex textureMutex;
+ QList<QSGTexture *> texturesToClean;
+
+ bool flashMode;
+ float renderAlpha;
+};
+
+
+/*!
+ \class QSGContext
+
+ \brief The QSGContext holds the scene graph entry points for one QML engine.
+
+ The context is not ready for use until it has a QGLContext. Once that happens,
+ the scene graph population can start.
+
+ \internal
+ */
+
+QSGContext::QSGContext(QObject *parent) :
+ QObject(*(new QSGContextPrivate), parent)
+{
+ Q_D(QSGContext);
+ d->engine.setContext(this);
+}
+
+
+QSGContext::~QSGContext()
+{
+ Q_D(QSGContext);
+ delete d->renderer;
+ delete d->rootNode;
+ cleanupTextures();
+ qDeleteAll(d->materials.values());
+}
+
+/*!
+ Returns the scene graph engine for this context.
+
+ The main purpose of the QSGEngine is to serve as a public API
+ to the QSGContext.
+
+ */
+QSGEngine *QSGContext::engine() const
+{
+ return const_cast<QSGEngine *>(&d_func()->engine);
+}
+
+/*!
+ Schedules the texture to be cleaned up on the rendering thread
+ at a later time.
+
+ The texture can be considered as deleted after this function has
+ been called.
+ */
+void QSGContext::schdelueTextureForCleanup(QSGTexture *texture)
+{
+ Q_D(QSGContext);
+ d->textureMutex.lock();
+ Q_ASSERT(!d->texturesToClean.contains(texture));
+ d->texturesToClean << texture;
+ d->textureMutex.unlock();
+}
+
+
+
+/*!
+ Deletes all textures that have been scheduled for cleanup
+ */
+void QSGContext::cleanupTextures()
+{
+ Q_D(QSGContext);
+ d->textureMutex.lock();
+ qDeleteAll(d->texturesToClean);
+ d->texturesToClean.clear();
+ d->textureMutex.unlock();
+}
+
+/*!
+ Returns the renderer. The renderer instance is created through the adaptation layer.
+ */
+QSGRenderer *QSGContext::renderer() const
+{
+ Q_D(const QSGContext);
+ return d->renderer;
+}
+
+
+/*!
+ Returns the root node. The root node instance is only created once the scene graph
+ context becomes ready.
+ */
+QSGRootNode *QSGContext::rootNode() const
+{
+ Q_D(const QSGContext);
+ return d->rootNode;
+}
+
+
+QGLContext *QSGContext::glContext() const
+{
+ Q_D(const QSGContext);
+ return d->gl;
+}
+
+/*!
+ Initializes the scene graph context with the GL context \a context. This also
+ emits the ready() signal so that the QML graph can start building scene graph nodes.
+ */
+void QSGContext::initialize(QGLContext *context)
+{
+ Q_D(QSGContext);
+
+ Q_ASSERT(!d->gl);
+
+ d->gl = context;
+
+ d->renderer = createRenderer();
+ d->renderer->setClearColor(Qt::white);
+
+ d->rootNode = new QSGRootNode();
+ d->renderer->setRootNode(d->rootNode);
+
+ emit ready();
+}
+
+
+/*!
+ Returns if the scene graph context is ready or not, meaning that it has a valid
+ GL context.
+ */
+bool QSGContext::isReady() const
+{
+ Q_D(const QSGContext);
+ return d->gl;
+}
+
+
+void QSGContext::renderNextFrame()
+{
+ Q_D(QSGContext);
+
+ emit d->engine.beforeRendering();
+
+ cleanupTextures();
+ d->renderer->renderScene();
+
+ emit d->engine.afterRendering();
+
+}
+
+/*!
+ Factory function for scene graph backends of the Rectangle element.
+ */
+QSGRectangleNode *QSGContext::createRectangleNode()
+{
+ return new QSGDefaultRectangleNode(this);
+}
+
+/*!
+ Factory function for scene graph backends of the Image element.
+ */
+QSGImageNode *QSGContext::createImageNode()
+{
+ return new QSGDefaultImageNode;
+}
+
+/*!
+ Factory function for scene graph backends of the Text elements;
+ */
+QSGGlyphNode *QSGContext::createGlyphNode()
+{
+ if (QSGDistanceFieldGlyphCache::distanceFieldEnabled()) {
+ QSGGlyphNode *node = new QSGDistanceFieldGlyphNode;
+ if (qApp->arguments().contains(QLatin1String("--subpixel-antialiasing")))
+ node->setPreferredAntialiasingMode(QSGGlyphNode::SubPixelAntialiasing);
+ return node;
+ } else {
+ return new QSGDefaultGlyphNode;
+ }
+}
+
+/*!
+ Factory function for the scene graph renderers.
+
+ The renderers are used for the toplevel renderer and once for every
+ QSGShaderEffectSource used in the QML scene.
+ */
+QSGRenderer *QSGContext::createRenderer()
+{
+ QMLRenderer *renderer = new QMLRenderer(this);
+ if (qApp->arguments().contains(QLatin1String("--opaque-front-to-back"))) {
+ printf("QSGContext: Sorting opaque nodes front to back...\n");
+ renderer->setSortFrontToBackEnabled(true);
+ }
+ return renderer;
+}
+
+
+
+/*!
+ Return true if the image provider supports direct decoding of images,
+ straight into textures without going through a QImage first.
+
+ If the implementation returns true from this function, the decodeImageToTexture() function
+ will be called to read data from a QIODevice, rather than QML decoding
+ the image using QImageReader and passing the result to setImage().
+
+ \warning This function will be called from outside the GUI and rendering threads
+ and must not make use of OpenGL.
+ */
+
+bool QSGContext::canDecodeImageToTexture() const
+{
+ return true;
+}
+
+
+
+/*!
+ Decode the data in \a dev directly to a texture provider of \a requestSize size.
+ The size of the decoded data should be written to \a impsize.
+
+ If the implementation fails to decode the image data, it should return 0. The
+ image data will then be decoded normally.
+
+ \warning This function will be called from outside the GUI and renderer threads
+ and must not make use of GL calls.
+ */
+
+QSGTexture *QSGContext::decodeImageToTexture(QIODevice *dev,
+ QSize *size,
+ const QSize &requestSize)
+{
+ Q_UNUSED(dev);
+ Q_UNUSED(size);
+ Q_UNUSED(requestSize);
+ return 0;
+}
+
+
+/*!
+ Factory function for texture objects.
+
+ If \a image is a valid image, the QSGTexture::setImage function
+ will be called with \a image as argument.
+ */
+QSGTexture *QSGContext::createTexture(const QImage &image) const
+{
+ QSGPlainTexture *t = new QSGPlainTexture();
+ if (!image.isNull())
+ t->setImage(image);
+ return t;
+}
+
+
+/*!
+ Returns a material shader for the given material.
+ */
+QSGMaterialShader *QSGContext::prepareMaterial(QSGMaterial *material)
+{
+ Q_D(QSGContext);
+ QSGMaterialType *type = material->type();
+ QSGMaterialShader *shader = d->materials.value(type);
+ if (shader)
+ return shader;
+
+ shader = material->createShader();
+ d->materials[type] = shader;
+ return shader;
+}
+
+/*!
+ Sets weither the scene graph should render with flashing update rectangles or not
+ */
+void QSGContext::setFlashModeEnabled(bool enabled)
+{
+ d_func()->flashMode = enabled;
+}
+
+
+/*!
+ Returns true if the scene graph should be rendered with flashing update rectangles
+ */
+bool QSGContext::isFlashModeEnabled() const
+{
+ return d_func()->flashMode;
+}
+
+
+/*!
+ Sets the toplevel opacity for rendering. This value will be multiplied into all
+ drawing calls where possible.
+
+ The default value is 1. Any other value will cause artifacts and is primarily
+ useful for debugging.
+ */
+void QSGContext::setRenderAlpha(qreal renderAlpha)
+{
+ d_func()->renderAlpha = renderAlpha;
+}
+
+
+/*!
+ Returns the toplevel opacity used for rendering.
+
+ The default value is 1.
+
+ \sa setRenderAlpha()
+ */
+qreal QSGContext::renderAlpha() const
+{
+ return d_func()->renderAlpha;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgcontext_p.h b/src/declarative/scenegraph/qsgcontext_p.h
new file mode 100644
index 0000000000..848dd17ad0
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontext_p.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCONTEXT_H
+#define QSGCONTEXT_H
+
+#include <QObject>
+#include <qabstractanimation.h>
+
+#include "qsgnode.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGContextPrivate;
+class QSGRectangleNode;
+class QSGImageNode;
+class QSGGlyphNode;
+class QSGRenderer;
+
+class QSGTexture;
+class QSGMaterial;
+class QSGMaterialShader;
+class QSGEngine;
+
+class QGLContext;
+
+class Q_DECLARATIVE_EXPORT QSGContext : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGContext)
+
+public:
+ explicit QSGContext(QObject *parent = 0);
+ ~QSGContext();
+
+ virtual void initialize(QGLContext *context);
+
+ QSGRenderer *renderer() const;
+
+ void setRootNode(QSGRootNode *node);
+ QSGRootNode *rootNode() const;
+
+ QSGEngine *engine() const;
+ QGLContext *glContext() const;
+
+ bool isReady() const;
+
+ QSGMaterialShader *prepareMaterial(QSGMaterial *material);
+
+ virtual void renderNextFrame();
+
+ virtual QSGRectangleNode *createRectangleNode();
+ virtual QSGImageNode *createImageNode();
+ virtual QSGGlyphNode *createGlyphNode();
+ virtual QSGRenderer *createRenderer();
+
+ virtual bool canDecodeImageToTexture() const;
+ virtual QSGTexture *decodeImageToTexture(QIODevice *dev,
+ QSize *size,
+ const QSize &requestSize);
+ virtual QSGTexture *createTexture(const QImage &image = QImage()) const;
+
+ static QSGContext *createDefaultContext();
+
+ void schdelueTextureForCleanup(QSGTexture *texture);
+ void cleanupTextures();
+
+ void setFlashModeEnabled(bool enabled);
+ bool isFlashModeEnabled() const;
+
+ void setRenderAlpha(qreal renderAlpha);
+ qreal renderAlpha() const;
+
+signals:
+ void ready();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGCONTEXT_H
diff --git a/src/declarative/scenegraph/qsgcontextplugin.cpp b/src/declarative/scenegraph/qsgcontextplugin.cpp
new file mode 100644
index 0000000000..287db68fa3
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontextplugin.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgcontextplugin_p.h"
+#include <private/qsgcontext_p.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/private/qfactoryloader_p.h>
+#include <QtCore/qlibraryinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGContextPlugin::QSGContextPlugin(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QSGContextPlugin::~QSGContextPlugin()
+{
+}
+
+#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QSGContextFactoryInterface_iid, QLatin1String("/scenegraph")))
+#endif
+
+/*!
+ \fn QSGContext *QSGContext::createDefaultContext()
+
+ Creates a default scene graph context for the current hardware.
+ This may load a device-specific plugin.
+*/
+QSGContext *QSGContext::createDefaultContext()
+{
+ const QStringList args = QApplication::arguments();
+ QString device;
+ for (int index = 0; index < args.count(); ++index) {
+ if (args.at(index).startsWith(QLatin1String("--device="))) {
+ device = args.at(index).mid(9);
+ break;
+ }
+ }
+ if (device.isEmpty())
+ device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE"));
+ if (device.isEmpty())
+ return new QSGContext();
+
+#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+ if (QSGContextFactoryInterface *factory
+ = qobject_cast<QSGContextFactoryInterface*>
+ (loader()->instance(device))) {
+ QSGContext *context = factory->create(device);
+ if (context)
+ return context;
+ }
+#ifndef QT_NO_DEBUG
+ qWarning("Could not create scene graph context for device '%s'"
+ " - check that plugins are installed correctly in %s",
+ qPrintable(device),
+ qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath)));
+#endif
+#endif // QT_NO_LIBRARY || QT_NO_SETTINGS
+
+ return new QSGContext();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgcontextplugin_p.h b/src/declarative/scenegraph/qsgcontextplugin_p.h
new file mode 100644
index 0000000000..e36bc13a9b
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontextplugin_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCONTEXTPLUGIN_H
+#define QSGCONTEXTPLUGIN_H
+
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGContext;
+
+struct Q_DECLARATIVE_EXPORT QSGContextFactoryInterface : public QFactoryInterface
+{
+ virtual QSGContext *create(const QString &key) const = 0;
+};
+
+#define QSGContextFactoryInterface_iid \
+ "com.trolltech.Qt.QSGContextFactoryInterface"
+Q_DECLARE_INTERFACE(QSGContextFactoryInterface, QSGContextFactoryInterface_iid)
+
+class Q_DECLARATIVE_EXPORT QSGContextPlugin : public QObject, public QSGContextFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QSGContextFactoryInterface:QFactoryInterface)
+public:
+ explicit QSGContextPlugin(QObject *parent = 0);
+ virtual ~QSGContextPlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QSGContext *create(const QString &key) const = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGCONTEXTPLUGIN_H
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode.cpp b/src/declarative/scenegraph/qsgdefaultglyphnode.cpp
new file mode 100644
index 0000000000..57482a9cf4
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultglyphnode_p.h"
+#include "qsgdefaultglyphnode_p_p.h"
+
+#include <qglshaderprogram.h>
+#include <private/qfont_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultGlyphNode::QSGDefaultGlyphNode()
+ : m_material(0)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
+{
+ m_geometry.setDrawingMode(GL_TRIANGLES);
+ setGeometry(&m_geometry);
+}
+
+QSGDefaultGlyphNode::~QSGDefaultGlyphNode()
+{
+ delete m_material;
+}
+
+void QSGDefaultGlyphNode::setColor(const QColor &color)
+{
+ m_color = color;
+ if (m_material != 0) {
+ m_material->setColor(color);
+ setMaterial(m_material); // Indicate the material state has changed
+ }
+}
+
+void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphs &glyphs)
+{
+ if (m_material != 0)
+ delete m_material;
+
+ QRawFont font = glyphs.font();
+ m_material = new QSGTextMaskMaterial(font);
+ m_material->setColor(m_color);
+
+ QRectF boundingRect;
+ m_material->populate(position, glyphs.glyphIndexes(), glyphs.positions(), geometry(),
+ &boundingRect, &m_baseLine);
+
+ setMaterial(m_material);
+ setBoundingRect(boundingRect);
+
+ markDirty(DirtyGeometry);
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("glyphs");
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp b/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp
new file mode 100644
index 0000000000..00090be9ea
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultglyphnode_p_p.h"
+
+#include <qglshaderprogram.h>
+
+#include <private/qtextureglyphcache_gl_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qglextensions_p.h>
+
+#include <private/qsgtexture_p.h>
+
+#include <private/qrawfont_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGTextMaskMaterialData : public QSGMaterialShader
+{
+public:
+ QSGTextMaskMaterialData();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+private:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ int m_matrix_id;
+ int m_color_id;
+ int m_textureScale_id;
+};
+
+const char *QSGTextMaskMaterialData::vertexShader() const {
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *QSGTextMaskMaterialData::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color * texture2D(texture, sampleCoord).a; \n"
+ "}";
+}
+
+char const *const *QSGTextMaskMaterialData::attributeNames() const
+{
+ static char const *const attr[] = { "vCoord", "tCoord", 0 };
+ return attr;
+}
+
+QSGTextMaskMaterialData::QSGTextMaskMaterialData()
+{
+}
+
+void QSGTextMaskMaterialData::initialize()
+{
+ m_matrix_id = m_program.uniformLocation("matrix");
+ m_color_id = m_program.uniformLocation("color");
+ m_textureScale_id = m_program.uniformLocation("textureScale");
+}
+
+void QSGTextMaskMaterialData::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGTextMaskMaterial *material = static_cast<QSGTextMaskMaterial *>(newEffect);
+ QSGTextMaskMaterial *oldMaterial = static_cast<QSGTextMaskMaterial *>(oldEffect);
+
+ if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) {
+ QVector4D color(material->color().redF(), material->color().greenF(),
+ material->color().blueF(), material->color().alphaF());
+ color *= state.opacity();
+ m_program.setUniformValue(m_color_id, color);
+ }
+
+ bool updated = material->ensureUpToDate();
+ Q_ASSERT(material->texture());
+
+ Q_ASSERT(oldMaterial == 0 || oldMaterial->texture());
+ if (updated
+ || oldMaterial == 0
+ || oldMaterial->texture()->textureId() != material->texture()->textureId()) {
+ m_program.setUniformValue(m_textureScale_id, QVector2D(1.0 / material->cacheTextureWidth(),
+ 1.0 / material->cacheTextureHeight()));
+ glBindTexture(GL_TEXTURE_2D, material->texture()->textureId());
+
+ // Set the mag/min filters to be linear. We only need to do this when the texture
+ // has been recreated.
+ if (updated) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ }
+
+ if (state.isMatrixDirty())
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+}
+
+QSGTextMaskMaterial::QSGTextMaskMaterial(const QRawFont &font)
+ : m_texture(0), m_glyphCache(), m_font(font)
+{
+ init();
+}
+
+QSGTextMaskMaterial::~QSGTextMaskMaterial()
+{
+}
+
+void QSGTextMaskMaterial::init()
+{
+ Q_ASSERT(m_font.isValid());
+
+ QFontEngineGlyphCache::Type type = QFontEngineGlyphCache::Raster_A8;
+ setFlag(Blending, true);
+
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ Q_ASSERT(ctx != 0);
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ if (fontD->fontEngine != 0) {
+ m_glyphCache = fontD->fontEngine->glyphCache(ctx, type, QTransform());
+ if (!m_glyphCache || m_glyphCache->cacheType() != type) {
+ m_glyphCache = new QGLTextureGlyphCache(ctx, type, QTransform());
+ fontD->fontEngine->setGlyphCache(ctx, m_glyphCache.data());
+ }
+ }
+
+#if !defined(QT_OPENGL_ES_2)
+ bool success = qt_resolve_version_2_0_functions(ctx)
+ && qt_resolve_buffer_extensions(ctx);
+ Q_ASSERT(success);
+ Q_UNUSED(success);
+#endif
+}
+
+void QSGTextMaskMaterial::populate(const QPointF &p,
+ const QVector<quint32> &glyphIndexes,
+ const QVector<QPointF> &glyphPositions,
+ QSGGeometry *geometry,
+ QRectF *boundingRect,
+ QPointF *baseLine)
+{
+ Q_ASSERT(m_font.isValid());
+ QVector<QFixedPoint> fixedPointPositions;
+ for (int i=0; i<glyphPositions.size(); ++i)
+ fixedPointPositions.append(QFixedPoint::fromPointF(glyphPositions.at(i)));
+
+ QTextureGlyphCache *cache = glyphCache();
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(),
+ fixedPointPositions.data());
+ cache->fillInPendingGlyphs();
+
+ int margin = cache->glyphMargin();
+
+ Q_ASSERT(geometry->indexType() == GL_UNSIGNED_SHORT);
+ geometry->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6);
+ QVector4D *vp = (QVector4D *)geometry->vertexDataAsTexturedPoint2D();
+ Q_ASSERT(geometry->stride() == sizeof(QVector4D));
+ ushort *ip = geometry->indexDataAsUShort();
+
+ QPointF position(p.x(), p.y() - m_font.ascent());
+ bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
+ for (int i=0; i<glyphIndexes.size(); ++i) {
+ QFixed subPixelPosition;
+ if (supportsSubPixelPositions)
+ subPixelPosition = cache->subPixelPositionForX(QFixed::fromReal(glyphPositions.at(i).x()));
+
+ QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
+ const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
+
+ QPointF glyphPosition = glyphPositions.at(i) + position;
+ int x = qRound(glyphPosition.x()) + c.baseLineX - margin;
+ int y = qRound(glyphPosition.y()) - c.baseLineY - margin;
+
+ *boundingRect |= QRectF(x + margin, y + margin, c.w, c.h);
+
+ float cx1 = x;
+ float cx2 = x + c.w;
+ float cy1 = y;
+ float cy2 = y + c.h;
+
+ float tx1 = c.x;
+ float tx2 = (c.x + c.w);
+ float ty1 = c.y;
+ float ty2 = (c.y + c.h);
+
+ if (baseLine->isNull())
+ *baseLine = glyphPosition;
+
+ vp[4 * i + 0] = QVector4D(cx1, cy1, tx1, ty1);
+ vp[4 * i + 1] = QVector4D(cx2, cy1, tx2, ty1);
+ vp[4 * i + 2] = QVector4D(cx1, cy2, tx1, ty2);
+ vp[4 * i + 3] = QVector4D(cx2, cy2, tx2, ty2);
+
+ int o = i * 4;
+ ip[6 * i + 0] = o + 0;
+ ip[6 * i + 1] = o + 2;
+ ip[6 * i + 2] = o + 3;
+ ip[6 * i + 3] = o + 3;
+ ip[6 * i + 4] = o + 1;
+ ip[6 * i + 5] = o + 0;
+ }
+}
+
+QSGMaterialType *QSGTextMaskMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QGLTextureGlyphCache *QSGTextMaskMaterial::glyphCache() const
+{
+ return static_cast<QGLTextureGlyphCache*>(m_glyphCache.data());
+}
+
+QSGMaterialShader *QSGTextMaskMaterial::createShader() const
+{
+ return new QSGTextMaskMaterialData;
+}
+
+int QSGTextMaskMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGTextMaskMaterial *other = static_cast<const QSGTextMaskMaterial *>(o);
+ if (m_glyphCache != other->m_glyphCache)
+ return m_glyphCache - other->m_glyphCache;
+ QRgb c1 = m_color.rgba();
+ QRgb c2 = other->m_color.rgba();
+ return int(c2 < c1) - int(c1 < c2);
+}
+
+bool QSGTextMaskMaterial::ensureUpToDate()
+{
+ QSize glyphCacheSize(glyphCache()->width(), glyphCache()->height());
+ if (glyphCacheSize != m_size) {
+ if (m_texture)
+ delete m_texture;
+ m_texture = new QSGPlainTexture();
+ m_texture->setTextureId(glyphCache()->texture());
+ m_texture->setTextureSize(QSize(glyphCache()->width(), glyphCache()->height()));
+ m_texture->setOwnsTexture(false);
+
+ m_size = glyphCacheSize;
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int QSGTextMaskMaterial::cacheTextureWidth() const
+{
+ return glyphCache()->width();
+}
+
+int QSGTextMaskMaterial::cacheTextureHeight() const
+{
+ return glyphCache()->height();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode_p.h b/src/declarative/scenegraph/qsgdefaultglyphnode_p.h
new file mode 100644
index 0000000000..9e93bc4368
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEFAULT_GLYPHNODE_H
+#define DEFAULT_GLYPHNODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QGlyphs;
+class QSGTextMaskMaterial;
+class QSGDefaultGlyphNode: public QSGGlyphNode
+{
+public:
+ QSGDefaultGlyphNode();
+ ~QSGDefaultGlyphNode();
+
+ virtual QPointF baseLine() const { return m_baseLine; }
+ virtual void setGlyphs(const QPointF &position, const QGlyphs &glyphs);
+ virtual void setColor(const QColor &color);
+
+ virtual void setPreferredAntialiasingMode(AntialiasingMode) { }
+
+private:
+ QGlyphs m_glyphs;
+ QPointF m_position;
+ QColor m_color;
+
+ QPointF m_baseLine;
+ QSGTextMaskMaterial *m_material;
+
+ QSGGeometry m_geometry;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // DEFAULT_GLYPHNODE_H
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h b/src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h
new file mode 100644
index 0000000000..b5f0d70020
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTMASKMATERIAL_H
+#define TEXTMASKMATERIAL_H
+
+#include <qsgmaterial.h>
+#include <qsgtexture.h>
+#include <qsggeometry.h>
+#include <qshareddata.h>
+#include <private/qsgtexture_p.h>
+#include <qrawfont.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFontEngineGlyphCache;
+class QGLTextureGlyphCache;
+class QFontEngine;
+class Geometry;
+class QSGTextMaskMaterial: public QSGMaterial
+{
+public:
+ QSGTextMaskMaterial(const QRawFont &font);
+ ~QSGTextMaskMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setColor(const QColor &color) { m_color = color; }
+ const QColor &color() const { return m_color; }
+
+ QSGTexture *texture() const { return m_texture; }
+
+ int cacheTextureWidth() const;
+ int cacheTextureHeight() const;
+
+ bool ensureUpToDate();
+
+ QGLTextureGlyphCache *glyphCache() const;
+ void populate(const QPointF &position,
+ const QVector<quint32> &glyphIndexes, const QVector<QPointF> &glyphPositions,
+ QSGGeometry *geometry, QRectF *boundingRect, QPointF *baseLine);
+
+private:
+ void init();
+
+ QSGPlainTexture *m_texture;
+ QExplicitlySharedDataPointer<QFontEngineGlyphCache> m_glyphCache;
+ QRawFont m_font;
+ QColor m_color;
+ QSize m_size;
+};
+
+QT_END_NAMESPACE
+
+#endif // TEXTMASKMATERIAL_H
diff --git a/src/declarative/scenegraph/qsgdefaultimagenode.cpp b/src/declarative/scenegraph/qsgdefaultimagenode.cpp
new file mode 100644
index 0000000000..a705e822c3
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultimagenode.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultimagenode_p.h"
+
+#include <private/qsgtextureprovider_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultImageNode::QSGDefaultImageNode()
+ : m_sourceRect(0, 0, 1, 1)
+ , m_dirtyGeometry(false)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+{
+ setMaterial(&m_materialO);
+ setOpaqueMaterial(&m_material);
+ setGeometry(&m_geometry);
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("image");
+#endif
+}
+
+void QSGDefaultImageNode::setTargetRect(const QRectF &rect)
+{
+ if (rect == m_targetRect)
+ return;
+ m_targetRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGDefaultImageNode::setSourceRect(const QRectF &rect)
+{
+ if (rect == m_sourceRect)
+ return;
+ m_sourceRect = rect;
+ m_dirtyGeometry = true;
+}
+
+
+void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.filtering() == filtering)
+ return;
+
+ m_material.setFiltering(filtering);
+ m_materialO.setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+
+void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.mipmapFiltering() == filtering)
+ return;
+
+ m_material.setMipmapFiltering(filtering);
+ m_materialO.setMipmapFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+
+void QSGDefaultImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
+{
+ if (m_material.verticalWrapMode() == wrapMode)
+ return;
+
+ m_material.setVerticalWrapMode(wrapMode);
+ m_materialO.setVerticalWrapMode(wrapMode);
+ markDirty(DirtyMaterial);
+}
+
+void QSGDefaultImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
+{
+ if (m_material.horizontalWrapMode() == wrapMode)
+ return;
+
+ m_material.setHorizontalWrapMode(wrapMode);
+ m_materialO.setHorizontalWrapMode(wrapMode);
+ markDirty(DirtyMaterial);
+}
+
+
+void QSGDefaultImageNode::setTexture(QSGTexture *texture)
+{
+ if (texture == m_material.texture())
+ return;
+
+ m_material.setTexture(texture);
+ m_materialO.setTexture(texture);
+ // Texture cleanup
+// if (!texture.isNull())
+// m_material.setBlending(texture->hasAlphaChannel());
+ markDirty(DirtyMaterial);
+
+ // Because the texture can be a different part of the atlas, we need to update it...
+ m_dirtyGeometry = true;
+}
+
+void QSGDefaultImageNode::update()
+{
+ if (m_dirtyGeometry)
+ updateGeometry();
+}
+
+void QSGDefaultImageNode::preprocess()
+{
+ bool doDirty = false;
+ QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(m_material.texture());
+ if (t) {
+ doDirty = t->updateTexture();
+ updateGeometry();
+ }
+// ### texture cleanup
+// bool alpha = m_material.blending();
+// if (!m_material->texture().isNull() && alpha != m_material.texture()->hasAlphaChannel()) {
+// m_material.setBlending(!alpha);
+// doDirty = true;
+// }
+
+ if (doDirty)
+ markDirty(DirtyMaterial);
+}
+
+void QSGDefaultImageNode::updateGeometry()
+{
+ const QSGTexture *t = m_material.texture();
+ if (!t) {
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry, QRectF(), QRectF());
+ } else {
+ QRectF textureRect = t->textureSubRect();
+ QRectF sr(textureRect.x() + m_sourceRect.x() * textureRect.width(),
+ textureRect.y() + m_sourceRect.y() * textureRect.height(),
+ m_sourceRect.width() * textureRect.width(),
+ m_sourceRect.height() * textureRect.height());
+
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr);
+ }
+ markDirty(DirtyGeometry);
+ m_dirtyGeometry = false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultimagenode_p.h b/src/declarative/scenegraph/qsgdefaultimagenode_p.h
new file mode 100644
index 0000000000..8eb2c89a2a
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultimagenode_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef DEFAULT_PIXMAPNODE_H
+#define DEFAULT_PIXMAPNODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+
+#include "qsgtexturematerial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGDefaultImageNode : public QSGImageNode
+{
+public:
+ QSGDefaultImageNode();
+ virtual void setTargetRect(const QRectF &rect);
+ virtual void setSourceRect(const QRectF &rect);
+ virtual void setTexture(QSGTexture *t);
+ virtual void update();
+
+ virtual void setMipmapFiltering(QSGTexture::Filtering filtering);
+ virtual void setFiltering(QSGTexture::Filtering filtering);
+ virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode);
+ virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode);
+
+ virtual void preprocess();
+
+private:
+ void updateGeometry();
+
+ QRectF m_targetRect;
+ QRectF m_sourceRect;
+
+ QSGTextureMaterial m_material;
+ QSGTextureMaterialWithOpacity m_materialO;
+
+ uint m_dirtyGeometry : 1;
+
+ QSGGeometry m_geometry;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp b/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp
new file mode 100644
index 0000000000..a0220cef1f
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp
@@ -0,0 +1,550 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+
+#include "qsgdefaultrectanglenode_p.h"
+
+#include <private/qsgvertexcolormaterial_p.h>
+#include "qsgtexturematerial.h"
+
+#include <private/qsgcontext_p.h>
+
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultRectangleNode::QSGDefaultRectangleNode(QSGContext *context)
+ : m_border(0)
+ , m_radius(0)
+ , m_pen_width(0)
+ , m_gradient_is_opaque(true)
+ , m_dirty_geometry(false)
+ , m_default_geometry(QSGGeometry::defaultAttributes_Point2D(), 4)
+ , m_context(context)
+{
+ setGeometry(&m_default_geometry);
+ setMaterial(&m_fill_material);
+ m_border_material.setColor(QColor(0, 0, 0));
+
+ m_material_type = TypeFlat;
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("rectangle");
+#endif
+}
+
+QSGDefaultRectangleNode::~QSGDefaultRectangleNode()
+{
+ switch (m_material_type) {
+ case TypeFlat:
+ break;
+ case TypeVertexGradient:
+ delete material();
+ break;
+ }
+ delete m_border;
+}
+
+QSGGeometryNode *QSGDefaultRectangleNode::border()
+{
+ if (!m_border) {
+ m_border = new QSGGeometryNode;
+ m_border->setMaterial(&m_border_material);
+ QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 0);
+ m_border->setGeometry(geometry);
+ m_border->setFlag(QSGNode::OwnsGeometry);
+ }
+ return m_border;
+}
+
+void QSGDefaultRectangleNode::setRect(const QRectF &rect)
+{
+ if (rect == m_rect)
+ return;
+ m_rect = rect;
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultRectangleNode::setColor(const QColor &color)
+{
+ if (color == m_fill_material.color())
+ return;
+ if (m_gradient_stops.isEmpty()) {
+ Q_ASSERT(m_material_type == TypeFlat);
+ m_fill_material.setColor(color);
+ setMaterial(&m_fill_material); // Indicate that the material state has changed.
+ }
+}
+
+void QSGDefaultRectangleNode::setPenColor(const QColor &color)
+{
+ if (color == m_border_material.color())
+ return;
+ m_border_material.setColor(color);
+ border()->setMaterial(&m_border_material); // Indicate that the material state has changed.
+}
+
+void QSGDefaultRectangleNode::setPenWidth(qreal width)
+{
+ if (width == m_pen_width)
+ return;
+ m_pen_width = width;
+ QSGNode *b = border();
+ if (m_pen_width <= 0 && b->parent())
+ removeChildNode(b);
+ else if (m_pen_width > 0 && !b->parent())
+ appendChildNode(b);
+ m_dirty_geometry = true;
+}
+
+
+void QSGDefaultRectangleNode::setGradientStops(const QGradientStops &stops)
+{
+ if (stops.constData() == m_gradient_stops.constData())
+ return;
+
+ m_gradient_stops = stops;
+
+ m_gradient_is_opaque = true;
+ for (int i = 0; i < stops.size(); ++i)
+ m_gradient_is_opaque &= stops.at(i).second.alpha() == 0xff;
+
+ if (stops.isEmpty()) {
+ // No gradient specified, use flat color.
+ if (m_material_type != TypeFlat) {
+
+ delete material();
+ delete opaqueMaterial();
+ setOpaqueMaterial(0);
+
+ setMaterial(&m_fill_material);
+ m_material_type = TypeFlat;
+
+ setGeometry(&m_default_geometry);
+ setFlag(OwnsGeometry, false);
+ }
+ } else {
+ if (m_material_type == TypeFlat) {
+ QSGVertexColorMaterial *material = new QSGVertexColorMaterial;
+ setMaterial(material);
+ m_material_type = TypeVertexGradient;
+ QSGGeometry *g = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0);
+ setGeometry(g);
+ setFlag(OwnsGeometry);
+ }
+ static_cast<QSGVertexColorMaterial *>(material())->setOpaque(m_gradient_is_opaque);
+ }
+
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultRectangleNode::setRadius(qreal radius)
+{
+ if (radius == m_radius)
+ return;
+ m_radius = radius;
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultRectangleNode::update()
+{
+ if (m_dirty_geometry) {
+ updateGeometry();
+ m_dirty_geometry = false;
+ }
+}
+
+struct Color4ub
+{
+ unsigned char r, g, b, a;
+};
+
+Color4ub operator *(Color4ub c, float t) { c.a *= t; c.r *= t; c.g *= t; c.b *= t; return c; }
+Color4ub operator +(Color4ub a, Color4ub b) { a.a += b.a; a.r += b.r; a.g += b.g; a.b += b.b; return a; }
+
+static inline Color4ub colorToColor4ub(const QColor &c)
+{
+ Color4ub color = { c.redF() * c.alphaF() * 255,
+ c.greenF() * c.alphaF() * 255,
+ c.blueF() * c.alphaF() * 255,
+ c.alphaF() * 255
+ };
+ return color;
+}
+
+struct Vertex
+{
+ QVector2D position;
+};
+
+struct ColorVertex
+{
+ QVector2D position;
+ Color4ub color;
+};
+
+void QSGDefaultRectangleNode::updateGeometry()
+{
+ // fast path for the simple case...
+ if ((m_pen_width == 0 || m_border_material.color().alpha() == 0)
+ && m_radius == 0
+ && m_material_type == TypeFlat) {
+ QSGGeometry::updateRectGeometry(&m_default_geometry, m_rect);
+ return;
+ }
+
+
+ // ### This part down below is not optimal, using QVectors and reallocation for
+ // every change, but its all going to be fixed up in rewrite...
+
+ QSGGeometry *fill = geometry();
+
+ // Check that the vertex type matches the material.
+ Q_ASSERT(m_material_type != TypeFlat || fill->stride() == sizeof(Vertex));
+ Q_ASSERT(m_material_type != TypeVertexGradient || fill->stride() == sizeof(ColorVertex));
+
+ QSGGeometry *borderGeometry = 0;
+ if (m_border) {
+ borderGeometry = border()->geometry();
+ Q_ASSERT(borderGeometry->stride() == sizeof(QSGGeometry::Point2D));
+ }
+
+ int fillVertexCount = 0;
+ int borderVertexCount = 0;
+ int borderIndexCount = 0;
+
+ QVector<uchar> fillVertexData;
+ QVector<Vertex> borderVertexData;
+ QVector<ushort> borderIndexData;
+
+ Color4ub fillColor = colorToColor4ub(m_fill_material.color());
+ const QGradientStops &stops = m_gradient_stops;
+
+ if (m_radius > 0) {
+ // Rounded corners.
+
+ // Radius should never exceeds half of the width or half of the height
+ qreal radius = qMin(qMin(m_rect.width() / 2, m_rect.height() / 2), m_radius);
+ QRectF innerRect = m_rect;
+ innerRect.adjust(radius, radius, -radius, -radius);
+ if (m_pen_width & 1) {
+ // Pen width is odd, so add the offset as documented.
+ innerRect.moveLeft(innerRect.left() + qreal(0.5));
+ innerRect.moveTop(innerRect.top() + qreal(0.5));
+ }
+
+ qreal innerRadius = radius - m_pen_width * qreal(0.5);
+ qreal outerRadius = radius + m_pen_width * qreal(0.5);
+
+ int segments = qMin(30, qCeil(outerRadius)); // Number of segments per corner.
+
+ /*
+
+ --+-__
+ | segment
+ | _+
+ --+-__ _- \
+ -+ segment
+ --------+ \ <- gradient line
+ +-----+
+ | |
+
+ */
+
+ // Overestimate the number of vertices and indices, reduce afterwards when the actual numbers are known.
+ if (m_pen_width) {
+ // The reason I add extra vertices where the gradient lines intersect the border is
+ // to avoid pixel sized gaps between the fill and the border caused by floating point
+ // inaccuracies.
+ borderVertexData.resize((segments + 1) * 2 * 4 + m_gradient_stops.size() * 2);
+ }
+ fillVertexData.resize(((segments + 1) * 4 + m_gradient_stops.size() * 2) * fill->stride());
+
+ Vertex *borderVertices = borderVertexData.data();
+ void *fillVertices = fillVertexData.data(); // Can be Vertex, ColorVertex or TextureVertex.
+
+
+ int nextGradientStop = 0;
+ qreal gradientPos = (radius - innerRadius) / (innerRect.height() + 2 * radius);
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
+ ++nextGradientStop;
+
+ qreal py = 0; // previous inner y-coordinate.
+ qreal plx = 0; // previous inner left x-coordinate.
+ qreal prx = 0; // previous inner right x-coordinate.
+
+ for (int part = 0; part < 2; ++part) {
+ for (int i = 0; i <= segments; ++i) {
+ //### Should change to calculate sin/cos only once.
+ qreal angle = qreal(0.5 * M_PI) * (part + i / qreal(segments));
+ qreal s = qFastSin(angle);
+ qreal c = qFastCos(angle);
+ qreal y = (part ? innerRect.bottom() : innerRect.top()) - innerRadius * c; // current inner y-coordinate.
+ qreal lx = innerRect.left() - innerRadius * s; // current inner left x-coordinate.
+ qreal rx = innerRect.right() + innerRadius * s; // current inner right x-coordinate.
+ qreal Y = (part ? innerRect.bottom() : innerRect.top()) - outerRadius * c; // current outer y-coordinate.
+ qreal lX = innerRect.left() - outerRadius * s; // current outer left x-coordinate.
+ qreal rX = innerRect.right() + outerRadius * s; // current outer right x-coordinate.
+
+ gradientPos = ((part ? innerRect.height() : 0) + radius - innerRadius * c) / (innerRect.height() + 2 * radius);
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos) {
+ // Insert vertices at gradient stops.
+ qreal gy = (innerRect.top() - radius) + stops.at(nextGradientStop).first * (innerRect.height() + 2 * radius);
+ Q_ASSERT(fillVertexCount >= 2);
+ qreal t = (gy - py) / (y - py);
+ qreal glx = plx * (1 - t) + t * lx;
+ qreal grx = prx * (1 - t) + t * rx;
+
+ if (m_pen_width) {
+ borderVertices[borderVertexCount++].position = QVector2D(grx, gy);
+ borderVertices[borderVertexCount++].position = QVector2D(glx, gy);
+
+ int first = borderIndexData.first();
+ borderIndexData.prepend(borderVertexCount - 1);
+ borderIndexData.prepend(first);
+
+ int last = borderIndexData.at(borderIndexData.size() - 2);
+ borderIndexData.append(last);
+ borderIndexData.append(borderVertexCount - 2);
+ }
+
+ Q_ASSERT(QSGVertexColorMaterial::is(material()));
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+
+ fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
+ vertices[fillVertexCount].position = QVector2D(grx, gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(glx, gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+
+ ++nextGradientStop;
+ }
+
+ if (m_pen_width) {
+ borderVertices[borderVertexCount++].position = QVector2D(rX, Y);
+ borderVertices[borderVertexCount++].position = QVector2D(lX, Y);
+ borderVertices[borderVertexCount++].position = QVector2D(rx, y);
+ borderVertices[borderVertexCount++].position = QVector2D(lx, y);
+
+ borderIndexData.prepend(borderVertexCount - 1);
+ borderIndexData.prepend(borderVertexCount - 3);
+ borderIndexData.append(borderVertexCount - 4);
+ borderIndexData.append(borderVertexCount - 2);
+ }
+
+ if (stops.isEmpty()) {
+ Q_ASSERT(m_material_type == TypeFlat);
+ Vertex *vertices = (Vertex *)fillVertices;
+ vertices[fillVertexCount++].position = QVector2D(rx, y);
+ vertices[fillVertexCount++].position = QVector2D(lx, y);
+ } else {
+ if (nextGradientStop == 0) {
+ fillColor = colorToColor4ub(stops.at(0).second);
+ } else if (nextGradientStop == stops.size()) {
+ fillColor = colorToColor4ub(stops.last().second);
+ } else {
+ const QGradientStop &prev = stops.at(nextGradientStop - 1);
+ const QGradientStop &next = stops.at(nextGradientStop);
+ qreal t = (gradientPos - prev.first) / (next.first - prev.first);
+ fillColor = (colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t);
+ }
+
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+ vertices[fillVertexCount].position = QVector2D(rx, y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(lx, y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ }
+
+ py = y;
+ plx = lx;
+ prx = rx;
+ }
+ }
+
+
+ if (m_pen_width) {
+ // Close border.
+ ushort first = borderIndexData.at(0);
+ ushort second = borderIndexData.at(1);
+ borderIndexData.append(first);
+ borderIndexData.append(second);
+
+ borderIndexCount = borderIndexData.size();
+ }
+
+ } else {
+
+ // Straight corners.
+ QRectF innerRect = m_rect;
+ QRectF outerRect = m_rect;
+
+ qreal halfPenWidth = 0;
+ if (m_pen_width) {
+ if (m_pen_width & 1) {
+ // Pen width is odd, so add the offset as documented.
+ innerRect.moveLeft(innerRect.left() + qreal(0.5));
+ innerRect.moveTop(innerRect.top() + qreal(0.5));
+ outerRect = innerRect;
+ }
+ halfPenWidth = m_pen_width * qreal(0.5);
+ innerRect.adjust(halfPenWidth, halfPenWidth, -halfPenWidth, -halfPenWidth);
+ outerRect.adjust(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth);
+ }
+
+ if (m_pen_width) {
+ borderVertexData.resize((2 + stops.size()) * 2 + 4);
+ borderIndexData.resize((2 + stops.size()) * 2 * 2 + 4);
+ }
+ fillVertexData.resize((2 + stops.size()) * 2 * fill->stride());
+
+ void *fillVertices = fillVertexData.data();
+ Vertex *borderVertices = (Vertex *) borderVertexData.data();
+ ushort *borderIndices = borderIndexData.data();
+
+ int nextGradientStop = 0;
+ qreal gradientPos = halfPenWidth / m_rect.height();
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
+ ++nextGradientStop;
+
+ for (int part = 0; part < 2; ++part) {
+ qreal y = (part ? innerRect.bottom() : innerRect.top());
+ gradientPos = (y - innerRect.top() + halfPenWidth) / m_rect.height();
+
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos) {
+ // Insert vertices at gradient stops.
+ qreal gy = (innerRect.top() - halfPenWidth) + stops.at(nextGradientStop).first * m_rect.height();
+ Q_ASSERT(fillVertexCount >= 2);
+
+ Q_ASSERT(QSGVertexColorMaterial::is(material()));
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+
+ fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
+ vertices[fillVertexCount].position = QVector2D(innerRect.right(), gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(innerRect.left(), gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+
+ if (m_pen_width) {
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.right(), gy);
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.left(), gy);
+ }
+
+ ++nextGradientStop;
+ }
+
+ if (stops.isEmpty()) {
+ Q_ASSERT(m_material_type == TypeFlat);
+ Vertex *vertices = (Vertex *)fillVertices;
+ vertices[fillVertexCount++].position = QVector2D(innerRect.right(), y);
+ vertices[fillVertexCount++].position = QVector2D(innerRect.left(), y);
+ } else {
+ if (nextGradientStop == 0) {
+ fillColor = colorToColor4ub(stops.at(0).second);
+ } else if (nextGradientStop == stops.size()) {
+ fillColor = colorToColor4ub(stops.last().second);
+ } else {
+ const QGradientStop &prev = stops.at(nextGradientStop - 1);
+ const QGradientStop &next = stops.at(nextGradientStop);
+ qreal t = (gradientPos - prev.first) / (next.first - prev.first);
+ fillColor = (colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t);
+ }
+
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+ vertices[fillVertexCount].position = QVector2D(innerRect.right(), y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(innerRect.left(), y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ }
+
+ if (m_pen_width) {
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.right(), y);
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.left(), y);
+ }
+ }
+
+ if (m_pen_width) {
+ // Add four corners.
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.right(), outerRect.top());
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.left(), outerRect.top());
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.right(), outerRect.bottom());
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.left(), outerRect.bottom());
+
+ for (int i = 0; i < fillVertexCount / 2; ++i) {
+ borderIndices[borderIndexCount++] = borderVertexCount - (i == 0 ? 4 : 2); // Upper or lower right corner.
+ borderIndices[borderIndexCount++] = 2 * i + 0;
+ }
+ for (int i = 0; i < fillVertexCount / 2; ++i) {
+ borderIndices[borderIndexCount++] = borderVertexCount - (i == 0 ? 1 : 3); // Lower or upper left corner.
+ borderIndices[borderIndexCount++] = fillVertexCount - 2 * i - 1;
+ }
+ borderIndices[borderIndexCount++] = fillVertexCount; // Upper right corner.
+ borderIndices[borderIndexCount++] = 0;
+ Q_ASSERT(fillVertexCount + 4 == borderVertexCount);
+ }
+ }
+
+ // Copy from temporary datastructures to geometry...
+ if (m_pen_width) {
+ borderGeometry->allocate(borderVertexCount, borderIndexCount);
+ memcpy(borderGeometry->indexData(), borderIndexData.constData(), borderIndexCount * sizeof(quint16));
+ memcpy(borderGeometry->vertexData(), borderVertexData.constData(), borderVertexCount * sizeof(Vertex));
+ m_border->markDirty(DirtyGeometry);
+ }
+
+ fill->allocate(fillVertexCount);
+ memcpy(fill->vertexData(), fillVertexData.constData(), fillVertexCount * fill->stride());
+
+ markDirty(DirtyGeometry);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultrectanglenode_p.h b/src/declarative/scenegraph/qsgdefaultrectanglenode_p.h
new file mode 100644
index 0000000000..3bf14947de
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultrectanglenode_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef DEFAULT_RECTANGLENODE_H
+#define DEFAULT_RECTANGLENODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+
+#include "qsgflatcolormaterial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMaterial;
+class QSGContext;
+
+class QSGDefaultRectangleNode : public QSGRectangleNode
+{
+public:
+ QSGDefaultRectangleNode(QSGContext *context);
+ ~QSGDefaultRectangleNode();
+
+ virtual void setRect(const QRectF &rect);
+ virtual void setColor(const QColor &color);
+ virtual void setPenColor(const QColor &color);
+ virtual void setPenWidth(qreal width);
+ virtual void setGradientStops(const QGradientStops &stops);
+ virtual void setRadius(qreal radius);
+ virtual void update();
+
+private:
+ enum {
+ TypeFlat,
+ TypeVertexGradient
+ };
+ QSGGeometryNode *border();
+
+ void updateGeometry();
+ void updateGradientTexture();
+
+ QSGGeometryNode *m_border;
+ QSGFlatColorMaterial m_border_material;
+ QSGFlatColorMaterial m_fill_material;
+
+ QRectF m_rect;
+ QGradientStops m_gradient_stops;
+ qreal m_radius;
+ int m_pen_width;
+
+ uint m_gradient_is_opaque : 1;
+ uint m_dirty_geometry : 1;
+
+ uint m_material_type : 2; // Only goes up to 3
+
+ QSGGeometry m_default_geometry;
+
+ QSGContext *m_context;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp
new file mode 100644
index 0000000000..957632c46f
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp
@@ -0,0 +1,956 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdistancefieldglyphcache_p.h"
+
+#include <qmath.h>
+#include <private/qtriangulator_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <qglshaderprogram.h>
+#include <private/qglengineshadersource_p.h>
+#include <private/qsgcontext_p.h>
+#include <private/qrawfont_p.h>
+#include <qglfunctions.h>
+#include <qglyphs.h>
+#include <qrawfont.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE 54
+#define QT_DISTANCEFIELD_DEFAULT_TILESIZE 64
+#define QT_DISTANCEFIELD_DEFAULT_SCALE 16
+#define QT_DISTANCEFIELD_DEFAULT_RADIUS 80
+#define QT_DISTANCEFIELD_HIGHGLYPHCOUNT 2000
+
+#define QT_DISTANCEFIELD_BASEFONTSIZE \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE * 2 : \
+ QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE)
+#define QT_DISTANCEFIELD_TILESIZE \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_TILESIZE * 2 : \
+ QT_DISTANCEFIELD_DEFAULT_TILESIZE)
+#define QT_DISTANCEFIELD_SCALE \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_SCALE / 2 : \
+ QT_DISTANCEFIELD_DEFAULT_SCALE)
+#define QT_DISTANCEFIELD_RADIUS \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_RADIUS / 2 : \
+ QT_DISTANCEFIELD_DEFAULT_RADIUS)
+
+static inline int qt_next_power_of_two(int v)
+{
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ ++v;
+ return v;
+}
+
+struct DFPoint
+{
+ float x, y;
+};
+
+struct DFVertex
+{
+ DFPoint p;
+ float d;
+};
+
+static void drawRectangle(float *bits, int width, int height, const DFVertex *v1, const DFVertex *v2, const DFVertex *v3, const DFVertex *v4)
+{
+ float minY = qMin(qMin(v1->p.y, v2->p.y), qMin(v3->p.y, v4->p.y));
+ if (v2->p.y == minY) {
+ const DFVertex *tmp = v1;
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = tmp;
+ } else if (v3->p.y == minY) {
+ const DFVertex *tmp1 = v1;
+ const DFVertex *tmp2 = v2;
+ v1 = v3;
+ v2 = v4;
+ v3 = tmp1;
+ v4 = tmp2;
+ } else if (v4->p.y == minY) {
+ const DFVertex *tmp = v4;
+ v4 = v3;
+ v3 = v2;
+ v2 = v1;
+ v1 = tmp;
+ }
+
+ /*
+ v1
+ / \
+ v4 v2
+ \ /
+ v3
+ */
+
+ int fromY = qMax(0, qCeil(v1->p.y));
+ int midY1 = qMin(height, qCeil(qMin(v2->p.y, v4->p.y)));
+ int midY2 = qMin(height, qCeil(qMax(v2->p.y, v4->p.y)));
+ int toY = qMin(height, qCeil(v3->p.y));
+
+ if (toY <= fromY)
+ return;
+
+ bits += width * fromY;
+ int y = fromY;
+
+ float leftDx = (v4->p.x - v1->p.x) / (v4->p.y - v1->p.y);
+ float leftDd = (v4->d - v1->d) / (v4->p.y - v1->p.y);
+ float leftX = v1->p.x + (fromY - v1->p.y) * leftDx;
+ float leftD = v1->d + (fromY - v1->p.y) * leftDd;
+
+ float rightDx = (v2->p.x - v1->p.x) / (v2->p.y - v1->p.y);
+ float rightDd = (v2->d - v1->d) / (v2->p.y - v1->p.y);
+ float rightX = v1->p.x + (fromY - v1->p.y) * rightDx;
+ float rightD = v1->d + (fromY - v1->p.y) * rightDd;
+
+ float dd = ((v2->d - v1->d) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->d - v1->d))
+ / ((v2->p.x - v1->p.x) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->p.x - v1->p.x));
+
+ for (; y < midY1; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+
+ if (midY1 == toY)
+ return;
+
+ if (v2->p.y > v4->p.y) {
+ // Long right edge.
+ leftDx = (v3->p.x - v4->p.x) / (v3->p.y - v4->p.y);
+ leftDd = (v3->d - v4->d) / (v3->p.y - v4->p.y);
+ leftX = v4->p.x + (midY1 - v4->p.y) * leftDx;
+ leftD = v4->d + (midY1 - v4->p.y) * leftDd;
+ } else {
+ // Long left edge.
+ rightDx = (v3->p.x - v2->p.x) / (v3->p.y - v2->p.y);
+ rightDd = (v3->d - v2->d) / (v3->p.y - v2->p.y);
+ rightX = v2->p.x + (midY1 - v2->p.y) * rightDx;
+ rightD = v2->d + (midY1 - v2->p.y) * rightDd;
+ }
+
+ for (; y < midY2; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+
+ if (midY2 == toY)
+ return;
+
+ if (v2->p.y > v4->p.y) {
+ // Long left edge.
+ rightDx = (v3->p.x - v2->p.x) / (v3->p.y - v2->p.y);
+ rightDd = (v3->d - v2->d) / (v3->p.y - v2->p.y);
+ rightX = v2->p.x + (midY2 - v2->p.y) * rightDx;
+ rightD = v2->d + (midY2 - v2->p.y) * rightDd;
+ } else {
+ // Long right edge.
+ leftDx = (v3->p.x - v4->p.x) / (v3->p.y - v4->p.y);
+ leftDd = (v3->d - v4->d) / (v3->p.y - v4->p.y);
+ leftX = v4->p.x + (midY2 - v4->p.y) * leftDx;
+ leftD = v4->d + (midY2 - v4->p.y) * leftDd;
+ }
+
+ for (; y < toY; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+}
+
+static void drawTriangle(float *bits, int width, int height, const DFVertex *v1, const DFVertex *v2, const DFVertex *v3)
+{
+ float minY = qMin(qMin(v1->p.y, v2->p.y), v3->p.y);
+ if (v2->p.y == minY) {
+ const DFVertex *tmp = v1;
+ v1 = v2;
+ v2 = v3;
+ v3 = tmp;
+ } else if (v3->p.y == minY) {
+ const DFVertex *tmp = v3;
+ v3 = v2;
+ v2 = v1;
+ v1 = tmp;
+ }
+
+ // v1
+ // / \
+ // v3--v2
+
+ int fromY = qMax(0, qCeil(v1->p.y));
+ int midY = qMin(height, qCeil(qMin(v2->p.y, v3->p.y)));
+ int toY = qMin(height, qCeil(qMax(v2->p.y, v3->p.y)));
+
+ if (toY <= fromY)
+ return;
+
+ float leftDx = (v3->p.x - v1->p.x) / (v3->p.y - v1->p.y);
+ float leftDd = (v3->d - v1->d) / (v3->p.y - v1->p.y);
+ float leftX = v1->p.x + (fromY - v1->p.y) * leftDx;
+ float leftD = v1->d + (fromY - v1->p.y) * leftDd;
+
+ float rightDx = (v2->p.x - v1->p.x) / (v2->p.y - v1->p.y);
+ float rightDd = (v2->d - v1->d) / (v2->p.y - v1->p.y);
+ float rightX = v1->p.x + (fromY - v1->p.y) * rightDx;
+ float rightD = v1->d + (fromY - v1->p.y) * rightDd;
+
+ float dd = ((v2->d - v1->d) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->d - v1->d))
+ / ((v2->p.x - v1->p.x) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->p.x - v1->p.x));
+
+ bits += width * fromY;
+ int y = fromY;
+ for (; y < midY; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+
+ if (midY == toY)
+ return;
+
+ if (v2->p.y > v3->p.y) {
+ // Long right edge.
+ leftDx = (v2->p.x - v3->p.x) / (v2->p.y - v3->p.y);
+ leftDd = (v2->d - v3->d) / (v2->p.y - v3->p.y);
+ leftX = v3->p.x + (midY - v3->p.y) * leftDx;
+ leftD = v3->d + (midY - v3->p.y) * leftDd;
+ } else {
+ // Long left edge.
+ rightDx = (v3->p.x - v2->p.x) / (v3->p.y - v2->p.y);
+ rightDd = (v3->d - v2->d) / (v3->p.y - v2->p.y);
+ rightX = v2->p.x + (midY - v2->p.y) * rightDx;
+ rightD = v2->d + (midY - v2->p.y) * rightDd;
+ }
+
+ for (; y < toY; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+}
+
+static QImage makeDistanceField(int imgSize, const QPainterPath &path, int dfScale, float offs)
+{
+ QImage image(imgSize, imgSize, QImage::Format_ARGB32_Premultiplied);
+
+ if (path.isEmpty()) {
+ image.fill(0);
+ return image;
+ }
+
+ QPolylineSet polys = qPolyline(path);
+
+ union Pacific {
+ float value;
+ QRgb color;
+ };
+ Pacific interior;
+ Pacific exterior;
+ interior.value = 127;
+ exterior.value = -127;
+
+ image.fill(exterior.color);
+
+ QPainter p(&image);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.translate(offs, offs);
+ p.scale(1 / qreal(dfScale), 1 / qreal(dfScale));
+ p.fillPath(path, QColor::fromRgba(interior.color));
+ p.end();
+
+ float *bits = (float *)image.bits();
+ const float angleStep = 15 * 3.141592653589793238f / 180;
+ const DFPoint rotation = { cos(angleStep), sin(angleStep) };
+
+ bool isShortData = polys.indices.type() == QVertexIndexVector::UnsignedShort;
+ const void *indices = polys.indices.data();
+ int index = 0;
+ QVector<DFPoint> normals;
+ QVector<DFVertex> vertices;
+ normals.reserve(polys.vertices.count());
+ vertices.reserve(polys.vertices.count());
+
+ while (index < polys.indices.size()) {
+ normals.clear();
+ vertices.clear();
+
+ // Find end of polygon.
+ int end = index;
+ if (isShortData) {
+ while (((quint16 *)indices)[end] != quint16(-1))
+ ++end;
+ } else {
+ while (((quint32 *)indices)[end] != quint32(-1))
+ ++end;
+ }
+
+ // Calculate vertex normals.
+ for (int next = index, prev = end - 1; next < end; prev = next++) {
+ quint32 fromVertexIndex = isShortData ? (quint32)((quint16 *)indices)[prev] : ((quint32 *)indices)[prev];
+ quint32 toVertexIndex = isShortData ? (quint32)((quint16 *)indices)[next] : ((quint32 *)indices)[next];
+ const qreal *from = &polys.vertices.at(fromVertexIndex * 2);
+ const qreal *to = &polys.vertices.at(toVertexIndex * 2);
+ DFPoint n;
+ n.x = float(to[1] - from[1]);
+ n.y = float(from[0] - to[0]);
+ if (n.x == 0 && n.y == 0)
+ continue;
+ float scale = offs / sqrt(n.x * n.x + n.y * n.y);
+ n.x *= scale;
+ n.y *= scale;
+ normals.append(n);
+
+ DFVertex v;
+ v.p.x = float(to[0] / dfScale) + offs - 0.5f;
+ v.p.y = float(to[1] / dfScale) + offs - 0.5f;
+ v.d = 0.0f;
+ vertices.append(v);
+ }
+
+ QVector<bool> isConvex(normals.count());
+ for (int next = 0, prev = normals.count() - 1; next < normals.count(); prev = next++)
+ isConvex[prev] = (normals.at(prev).x * normals.at(next).y - normals.at(prev).y * normals.at(next).x > 0);
+
+ // Draw quads.
+ for (int next = 0, prev = normals.count() - 1; next < normals.count(); prev = next++) {
+ DFPoint n = normals.at(next);
+ DFVertex intPrev = vertices.at(prev);
+ DFVertex extPrev = vertices.at(prev);
+ DFVertex intNext = vertices.at(next);
+ DFVertex extNext = vertices.at(next);
+
+ extPrev.p.x += n.x;
+ extPrev.p.y += n.y;
+ intPrev.p.x -= n.x;
+ intPrev.p.y -= n.y;
+ extNext.p.x += n.x;
+ extNext.p.y += n.y;
+ intNext.p.x -= n.x;
+ intNext.p.y -= n.y;
+ extPrev.d = 127;
+ extNext.d = 127;
+ intPrev.d = -127;
+ intNext.d = -127;
+
+ drawRectangle(bits, image.width(), image.height(),
+ &vertices.at(prev), &extPrev, &extNext, &vertices.at(next));
+
+ drawRectangle(bits, image.width(), image.height(),
+ &intPrev, &vertices.at(prev), &vertices.at(next), &intNext);
+
+ if (isConvex.at(prev)) {
+ DFVertex v = extPrev;
+ for (;;) {
+ DFPoint rn = { n.x * rotation.x + n.y * rotation.y,
+ n.y * rotation.x - n.x * rotation.y };
+ n = rn;
+ if (n.x * normals.at(prev).y - n.y * normals.at(prev).x >= -0.001) {
+ v.p.x = vertices.at(prev).p.x + normals.at(prev).x;
+ v.p.y = vertices.at(prev).p.y + normals.at(prev).y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &v, &extPrev);
+ break;
+ }
+
+ v.p.x = vertices.at(prev).p.x + n.x;
+ v.p.y = vertices.at(prev).p.y + n.y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &v, &extPrev);
+ extPrev = v;
+ }
+ } else {
+ DFVertex v = intPrev;
+ for (;;) {
+ DFPoint rn = { n.x * rotation.x - n.y * rotation.y,
+ n.y * rotation.x + n.x * rotation.y };
+ n = rn;
+ if (n.x * normals.at(prev).y - n.y * normals.at(prev).x <= 0.001) {
+ v.p.x = vertices.at(prev).p.x - normals.at(prev).x;
+ v.p.y = vertices.at(prev).p.y - normals.at(prev).y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &intPrev, &v);
+ break;
+ }
+
+ v.p.x = vertices.at(prev).p.x - n.x;
+ v.p.y = vertices.at(prev).p.y - n.y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &intPrev, &v);
+ intPrev = v;
+ }
+ }
+ }
+ index = end + 1;
+ }
+
+ for (int y = 0; y < image.height(); ++y) {
+ QRgb *iLine = (QRgb *)image.scanLine(y);
+ float *fLine = (float *)iLine;
+ for (int x = 0; x < image.width(); ++x)
+ iLine[x] = QRgb(fLine[x] + 127.5) << 24;
+ }
+
+ return image;
+}
+
+static void convert_to_Format_Alpha(QImage *image)
+{
+ const int width = image->width();
+ const int height = image->height();
+ uchar *data = image->bits();
+
+ for (int i = 0; i < height; ++i) {
+ uchar *o = data + i * width;
+ for (int x = 0; x < width; ++x)
+ o[x] = (uchar)qAlpha(image->pixel(x, i));
+ }
+}
+
+static bool fontHasNarrowOutlines(const QRawFont &f)
+{
+ return true;
+ QRawFont font = f;
+ font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE);
+ Q_ASSERT(font.isValid());
+
+ QVector<quint32> glyphIndices = font.glyphIndexesForString(QLatin1String("O"));
+ if (glyphIndices.size() < 1)
+ return false;
+
+ QImage im = font.alphaMapForGlyph(glyphIndices.at(0), QRawFont::PixelAntialiasing);
+ if (im.isNull())
+ return false;
+
+ int minHThick = 999;
+ int minVThick = 999;
+
+ int thick = 0;
+ bool in = false;
+ int y = (im.height() + 1) / 2;
+ for (int x = 0; x < im.width(); ++x) {
+ int a = qAlpha(im.pixel(x, y));
+ if (a > 127) {
+ in = true;
+ ++thick;
+ } else if (in) {
+ in = false;
+ minHThick = qMin(minHThick, thick);
+ thick = 0;
+ }
+ }
+
+ thick = 0;
+ in = false;
+ int x = (im.width() + 1) / 2;
+ for (int y = 0; y < im.height(); ++y) {
+ int a = qAlpha(im.pixel(x, y));
+ if (a > 127) {
+ in = true;
+ ++thick;
+ } else if (in) {
+ in = false;
+ minVThick = qMin(minVThick, thick);
+ thick = 0;
+ }
+ }
+
+ return minHThick == 1 || minVThick == 1;
+}
+
+DEFINE_BOOL_CONFIG_OPTION(disableDistanceField, QML_DISABLE_DISTANCEFIELD)
+
+QHash<QString, QSGDistanceFieldGlyphCache *> QSGDistanceFieldGlyphCache::m_caches;
+QHash<QString, QGLContextGroupResource<QSGDistanceFieldGlyphCache::DistanceFieldTextureData> > QSGDistanceFieldGlyphCache::m_textures_data;
+
+static QString fontKey(const QRawFont &font)
+{
+ QString key;
+
+ key = font.familyName();
+ key.remove(QLatin1String(" "));
+ QString italic = font.style() == QFont::StyleItalic ? QLatin1String("i") : QLatin1String("");
+ QString bold = font.weight() > QFont::Normal ? QLatin1String("b") : QLatin1String("");
+ key += bold + italic + QString::number(qreal(font.pixelSize()));
+
+ return key;
+}
+
+QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCache::get(const QGLContext *ctx, const QRawFont &font)
+{
+ QString key = QString::number(long(ctx), 16) + fontKey(font);
+ QHash<QString, QSGDistanceFieldGlyphCache *>::iterator atlas = m_caches.find(key);
+ if (atlas == m_caches.end())
+ atlas = m_caches.insert(key, new QSGDistanceFieldGlyphCache(ctx, font));
+
+ return atlas.value();
+}
+
+QSGDistanceFieldGlyphCache::DistanceFieldTextureData *QSGDistanceFieldGlyphCache::textureData()
+{
+ return m_textures_data[m_distanceFieldKey].value(ctx);
+}
+
+QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(const QGLContext *c, const QRawFont &font)
+ : QObject()
+ , m_maxTextureSize(0)
+ , ctx(c)
+ , m_blitProgram(0)
+{
+ Q_ASSERT(font.isValid());
+ m_font = font;
+
+ QString basename = m_font.familyName();
+ basename.remove(QLatin1String(" "));
+ QString italic = m_font.style() == QFont::StyleItalic ? QLatin1String("i") : QLatin1String("");
+ QString bold = m_font.weight() > QFont::Normal ? QLatin1String("b") : QLatin1String("");
+ m_distanceFieldKey = basename + bold + italic;
+ m_textureData = textureData();
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ m_glyphCount = fontD->fontEngine->glyphCount();
+
+ m_textureData->doubleGlyphResolution = fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
+
+ m_referenceFont = m_font;
+ m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE);
+ Q_ASSERT(m_referenceFont.isValid());
+
+ m_vertexCoordinateArray[0] = -1.0f;
+ m_vertexCoordinateArray[1] = -1.0f;
+ m_vertexCoordinateArray[2] = 1.0f;
+ m_vertexCoordinateArray[3] = -1.0f;
+ m_vertexCoordinateArray[4] = 1.0f;
+ m_vertexCoordinateArray[5] = 1.0f;
+ m_vertexCoordinateArray[6] = -1.0f;
+ m_vertexCoordinateArray[7] = 1.0f;
+
+ m_textureCoordinateArray[0] = 0.0f;
+ m_textureCoordinateArray[1] = 0.0f;
+ m_textureCoordinateArray[2] = 1.0f;
+ m_textureCoordinateArray[3] = 0.0f;
+ m_textureCoordinateArray[4] = 1.0f;
+ m_textureCoordinateArray[5] = 1.0f;
+ m_textureCoordinateArray[6] = 0.0f;
+ m_textureCoordinateArray[7] = 1.0f;
+
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ this, SLOT(onContextDestroyed(const QGLContext*)));
+}
+
+QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
+{
+ delete m_blitProgram;
+}
+
+void QSGDistanceFieldGlyphCache::onContextDestroyed(const QGLContext *context)
+{
+ if (context != ctx)
+ return;
+
+ QString key = QString::number(long(context), 16) + fontKey(m_font);
+ m_caches.remove(key);
+ deleteLater();
+}
+
+GLuint QSGDistanceFieldGlyphCache::texture()
+{
+ return m_textureData->texture;
+}
+
+QSize QSGDistanceFieldGlyphCache::textureSize() const
+{
+ return m_textureData->size;
+}
+
+int QSGDistanceFieldGlyphCache::maxTextureSize() const
+{
+ if (!m_maxTextureSize)
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
+ return m_maxTextureSize;
+}
+
+QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph)
+{
+ QHash<glyph_t, Metrics>::iterator metric = m_metrics.find(glyph);
+ if (metric == m_metrics.end()) {
+ QPainterPath path = m_font.pathForGlyph(glyph);
+
+ Metrics m;
+ m.width = path.boundingRect().width();
+ m.height = path.boundingRect().height();
+ m.baselineX = path.boundingRect().x();
+ m.baselineY = -path.boundingRect().y();
+
+ metric = m_metrics.insert(glyph, m);
+ }
+
+ return metric.value();
+}
+
+QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph)
+{
+ return m_textureData->texCoords.value(glyph);
+}
+
+QImage QSGDistanceFieldGlyphCache::renderDistanceFieldGlyph(glyph_t glyph) const
+{
+ QRawFont renderFont = m_font;
+ renderFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE * QT_DISTANCEFIELD_SCALE);
+
+ QPainterPath path = renderFont.pathForGlyph(glyph);
+ path.translate(-path.boundingRect().topLeft());
+ path.setFillRule(Qt::WindingFill);
+
+ QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE,
+ path,
+ QT_DISTANCEFIELD_SCALE,
+ QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE));
+ return im;
+}
+
+qreal QSGDistanceFieldGlyphCache::fontScale() const
+{
+ return qreal(m_font.pixelSize()) / QT_DISTANCEFIELD_BASEFONTSIZE;
+}
+
+int QSGDistanceFieldGlyphCache::distanceFieldRadius() const
+{
+ return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE;
+}
+
+void QSGDistanceFieldGlyphCache::populate(int count, const glyph_t *glyphs)
+{
+ for (int i = 0; i < count; ++i) {
+ glyph_t glyphIndex = glyphs[i];
+ if (glyphIndex >= glyphCount()) {
+ qWarning("Warning: distance-field glyph is not available with index %d", glyphIndex);
+ continue;
+ }
+
+ if (++m_textureData->glyphRefCount[glyphIndex] == 1)
+ m_textureData->unusedGlyphs.remove(glyphIndex);
+
+ if (m_textureData->texCoords.contains(glyphIndex)
+ || (cacheIsFull() && m_textureData->unusedGlyphs.isEmpty()))
+ continue;
+
+ QPainterPath path = m_referenceFont.pathForGlyph(glyphIndex);
+ if (path.isEmpty()) {
+ m_textureData->texCoords.insert(glyphIndex, TexCoord());
+ continue;
+ }
+
+ TexCoord c;
+ c.xMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE);
+ c.yMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE);
+ c.x = m_textureData->currX;
+ c.y = m_textureData->currY;
+ c.width = path.boundingRect().width();
+ c.height = path.boundingRect().height();
+
+ if (!cacheIsFull()) {
+ m_textureData->currX += QT_DISTANCEFIELD_TILESIZE;
+ if (m_textureData->currX >= maxTextureSize()) {
+ m_textureData->currX = 0;
+ m_textureData->currY += QT_DISTANCEFIELD_TILESIZE;
+ }
+ } else {
+ // Recycle glyphs
+ if (!m_textureData->unusedGlyphs.isEmpty()) {
+ glyph_t unusedGlyph = *m_textureData->unusedGlyphs.constBegin();
+ TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
+ c.x = unusedCoord.x;
+ c.y = unusedCoord.y;
+ m_textureData->unusedGlyphs.remove(unusedGlyph);
+ m_textureData->texCoords.remove(unusedGlyph);
+ }
+ }
+
+ if (c.y < maxTextureSize()) {
+ m_textureData->texCoords.insert(glyphIndex, c);
+ m_textureData->pendingGlyphs.insert(glyphIndex);
+ }
+ }
+}
+
+void QSGDistanceFieldGlyphCache::derefGlyphs(int count, const glyph_t *glyphs)
+{
+ for (int i = 0; i < count; ++i)
+ if (--m_textureData->glyphRefCount[glyphs[i]] == 0 && !glyphTexCoord(glyphs[i]).isNull())
+ m_textureData->unusedGlyphs.insert(glyphs[i]);
+}
+
+void QSGDistanceFieldGlyphCache::createTexture(int width, int height)
+{
+ if (ctx->d_ptr->workaround_brokenFBOReadBack && m_textureData->image.isNull())
+ m_textureData->image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
+
+ while (glGetError() != GL_NO_ERROR) { }
+
+ glGenTextures(1, &m_textureData->texture);
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ QVarLengthArray<uchar> data(width * height);
+ for (int i = 0; i < data.size(); ++i)
+ data[i] = 0;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ m_textureData->size = QSize(width, height);
+
+ GLuint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures(1, &m_textureData->texture);
+ m_textureData->texture = 0;
+ }
+
+}
+
+void QSGDistanceFieldGlyphCache::resizeTexture(int width, int height)
+{
+ int oldWidth = m_textureData->size.width();
+ int oldHeight = m_textureData->size.height();
+ if (width == oldWidth && height == oldHeight)
+ return;
+
+ GLuint oldTexture = m_textureData->texture;
+ createTexture(width, height);
+
+ if (!oldTexture)
+ return;
+
+ if (ctx->d_ptr->workaround_brokenFBOReadBack) {
+ m_textureData->image = m_textureData->image.copy(0, 0, width, height);
+ QImage copy = m_textureData->image.copy(0, 0, oldWidth, oldHeight);
+ convert_to_Format_Alpha(&copy);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, copy.constBits());
+ glDeleteTextures(1, &oldTexture);
+ return;
+ }
+
+ if (!m_textureData->fbo)
+ ctx->functions()->glGenFramebuffers(1, &m_textureData->fbo);
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_textureData->fbo);
+
+ GLuint tmp_texture;
+ glGenTextures(1, &tmp_texture);
+ glBindTexture(GL_TEXTURE_2D, tmp_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, tmp_texture, 0);
+
+ ctx->functions()->glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, oldTexture);
+
+ // save current render states
+ GLboolean stencilTestEnabled;
+ GLboolean depthTestEnabled;
+ GLboolean scissorTestEnabled;
+ GLboolean blendEnabled;
+ GLint viewport[4];
+ glGetBooleanv(GL_STENCIL_TEST, &stencilTestEnabled);
+ glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled);
+ glGetBooleanv(GL_SCISSOR_TEST, &scissorTestEnabled);
+ glGetBooleanv(GL_BLEND, &blendEnabled);
+ glGetIntegerv(GL_VIEWPORT, &viewport[0]);
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+
+ glViewport(0, 0, oldWidth, oldHeight);
+
+ if (m_blitProgram == 0) {
+ m_blitProgram = new QGLShaderProgram;
+
+ {
+ QString source;
+ source.append(QLatin1String(qglslMainWithTexCoordsVertexShader));
+ source.append(QLatin1String(qglslUntransformedPositionVertexShader));
+
+ QGLShader *vertexShader = new QGLShader(QGLShader::Vertex, m_blitProgram);
+ vertexShader->compileSourceCode(source);
+
+ m_blitProgram->addShader(vertexShader);
+ }
+
+ {
+ QString source;
+ source.append(QLatin1String(qglslMainFragmentShader));
+ source.append(QLatin1String(qglslImageSrcFragmentShader));
+
+ QGLShader *fragmentShader = new QGLShader(QGLShader::Fragment, m_blitProgram);
+ fragmentShader->compileSourceCode(source);
+
+ m_blitProgram->addShader(fragmentShader);
+ }
+
+ m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+
+ m_blitProgram->link();
+ }
+
+ ctx->functions()->glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_vertexCoordinateArray);
+ ctx->functions()->glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_textureCoordinateArray);
+
+ m_blitProgram->bind();
+ m_blitProgram->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
+ m_blitProgram->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
+ m_blitProgram->disableAttributeArray(int(QT_OPACITY_ATTR));
+ m_blitProgram->setUniformValue("imageTexture", GLuint(0));
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+
+ ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, 0);
+ glDeleteTextures(1, &tmp_texture);
+ glDeleteTextures(1, &oldTexture);
+
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+
+ // restore render states
+ if (stencilTestEnabled)
+ glEnable(GL_STENCIL_TEST);
+ if (depthTestEnabled)
+ glEnable(GL_DEPTH_TEST);
+ if (scissorTestEnabled)
+ glEnable(GL_SCISSOR_TEST);
+ if (blendEnabled)
+ glEnable(GL_BLEND);
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+}
+
+void QSGDistanceFieldGlyphCache::updateCache()
+{
+ if (m_textureData->pendingGlyphs.isEmpty())
+ return;
+
+ int requiredWidth = m_textureData->currY == 0 ? m_textureData->currX : maxTextureSize();
+ int requiredHeight = qMin(maxTextureSize(), m_textureData->currY + QT_DISTANCEFIELD_TILESIZE);
+
+ resizeTexture((requiredWidth), (requiredHeight));
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ QSet<glyph_t>::const_iterator i = m_textureData->pendingGlyphs.constBegin();
+ for (; i != m_textureData->pendingGlyphs.constEnd(); ++i) {
+ QImage glyph = renderDistanceFieldGlyph(*i);
+ TexCoord c = m_textureData->texCoords.value(*i);
+
+ if (ctx->d_ptr->workaround_brokenFBOReadBack) {
+ QPainter p(&m_textureData->image);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.drawImage(c.x, c.y, glyph);
+ p.end();
+ }
+
+ convert_to_Format_Alpha(&glyph);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
+ }
+ m_textureData->pendingGlyphs.clear();
+}
+
+bool QSGDistanceFieldGlyphCache::useWorkaroundBrokenFBOReadback() const
+{
+ return ctx->d_ptr->workaround_brokenFBOReadBack;
+}
+
+bool QSGDistanceFieldGlyphCache::distanceFieldEnabled()
+{
+ return !disableDistanceField();
+}
+
+int QSGDistanceFieldGlyphCache::glyphCount() const
+{
+ return m_glyphCount;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h
new file mode 100644
index 0000000000..60e5b5921a
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DISTANCEFIELDGLYPHCACHE_H
+#define DISTANCEFIELDGLYPHCACHE_H
+
+#include <qgl.h>
+#include <qrawfont.h>
+#include <private/qgl_p.h>
+#include <private/qfont_p.h>
+#include <private/qfontengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLShaderProgram;
+
+class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCache : public QObject
+{
+ Q_OBJECT
+public:
+ ~QSGDistanceFieldGlyphCache();
+
+ static QSGDistanceFieldGlyphCache *get(const QGLContext *ctx, const QRawFont &font);
+
+ struct Metrics {
+ qreal width;
+ qreal height;
+ qreal baselineX;
+ qreal baselineY;
+
+ bool isNull() const { return width == 0 || height == 0; }
+ };
+ Metrics glyphMetrics(glyph_t glyph);
+
+ struct TexCoord {
+ qreal x;
+ qreal y;
+ qreal width;
+ qreal height;
+ qreal xMargin;
+ qreal yMargin;
+
+ TexCoord() : x(0), y(0), width(0), height(0), xMargin(0), yMargin(0) { }
+
+ bool isNull() const { return width == 0 || height == 0; }
+ };
+ TexCoord glyphTexCoord(glyph_t glyph);
+
+ GLuint texture();
+ QSize textureSize() const;
+ int maxTextureSize() const;
+ qreal fontScale() const;
+ int distanceFieldRadius() const;
+ QImage renderDistanceFieldGlyph(glyph_t glyph) const;
+
+ int glyphCount() const;
+
+ void populate(int count, const glyph_t *glyphs);
+ void derefGlyphs(int count, const glyph_t *glyphs);
+ void updateCache();
+
+ bool cacheIsFull() const { return m_textureData->currY >= maxTextureSize(); }
+
+ bool useWorkaroundBrokenFBOReadback() const;
+
+ static bool distanceFieldEnabled();
+
+private Q_SLOTS:
+ void onContextDestroyed(const QGLContext *context);
+
+private:
+ QSGDistanceFieldGlyphCache(const QGLContext *c, const QRawFont &font);
+
+ void createTexture(int width, int height);
+ void resizeTexture(int width, int height);
+
+ static QHash<QString, QSGDistanceFieldGlyphCache *> m_caches;
+
+ QRawFont m_font;
+ QRawFont m_referenceFont;
+
+ QString m_distanceFieldKey;
+ int m_glyphCount;
+ QHash<glyph_t, Metrics> m_metrics;
+ mutable int m_maxTextureSize;
+
+ struct DistanceFieldTextureData {
+ GLuint texture;
+ GLuint fbo;
+ QSize size;
+ QHash<glyph_t, TexCoord> texCoords;
+ QSet<glyph_t> pendingGlyphs;
+ QHash<glyph_t, quint32> glyphRefCount;
+ QSet<glyph_t> unusedGlyphs;
+ int currX;
+ int currY;
+ QImage image;
+ bool doubleGlyphResolution;
+
+ DistanceFieldTextureData(const QGLContext *)
+ : texture(0)
+ , fbo(0)
+ , currX(0)
+ , currY(0)
+ , doubleGlyphResolution(false)
+ { }
+ };
+ DistanceFieldTextureData *textureData();
+ DistanceFieldTextureData *m_textureData;
+ static QHash<QString, QGLContextGroupResource<DistanceFieldTextureData> > m_textures_data;
+
+ const QGLContext *ctx;
+ QGLShaderProgram *m_blitProgram;
+ GLfloat m_vertexCoordinateArray[8];
+ GLfloat m_textureCoordinateArray[8];
+
+};
+
+QT_END_NAMESPACE
+
+#endif // DISTANCEFIELDGLYPHCACHE_H
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp
new file mode 100644
index 0000000000..ed2dba1ea3
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdistancefieldglyphnode_p.h"
+#include "qsgdistancefieldglyphnode_p_p.h"
+#include "qsgdistancefieldglyphcache_p.h"
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode()
+ : m_material(0)
+ , m_glyph_cache(0)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
+ , m_style(QSGText::Normal)
+ , m_antialiasingMode(GrayAntialiasing)
+{
+ m_geometry.setDrawingMode(GL_TRIANGLES);
+ setGeometry(&m_geometry);
+
+#ifndef QT_OPENGL_ES
+ setPreferredAntialiasingMode(QSGGlyphNode::SubPixelAntialiasing);
+#endif
+}
+
+QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode()
+{
+ delete m_material;
+ if (m_glyph_cache) {
+ const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
+ m_glyph_cache->derefGlyphs(glyphIndexes.count(), glyphIndexes.constData());
+ }
+}
+
+void QSGDistanceFieldGlyphNode::setColor(const QColor &color)
+{
+ m_color = color;
+ if (m_material != 0) {
+ m_material->setColor(color);
+ setMaterial(m_material); // Indicate the material state has changed
+ }
+}
+
+void QSGDistanceFieldGlyphNode::setPreferredAntialiasingMode(AntialiasingMode mode)
+{
+ if (mode == m_antialiasingMode)
+ return;
+ m_antialiasingMode = mode;
+ updateMaterial();
+}
+
+void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphs &glyphs)
+{
+ QRawFont font = glyphs.font();
+ m_position = QPointF(position.x(), position.y() - font.ascent());
+ m_glyphs = glyphs;
+
+ updateFont();
+ updateGeometry();
+ updateMaterial();
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("glyphs");
+#endif
+}
+
+void QSGDistanceFieldGlyphNode::setStyle(QSGText::TextStyle style)
+{
+ m_style = style;
+}
+
+void QSGDistanceFieldGlyphNode::setStyleColor(const QColor &color)
+{
+ m_styleColor = color;
+}
+
+void QSGDistanceFieldGlyphNode::updateGeometry()
+{
+ Q_ASSERT(m_glyph_cache);
+
+ QSGGeometry *g = geometry();
+ QRectF boundingRect;
+
+ const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
+
+ m_glyph_cache->populate(glyphIndexes.count(), glyphIndexes.constData());
+
+ Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT);
+ g->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6);
+ QVector4D *vp = (QVector4D *)g->vertexData();
+ ushort *ip = g->indexDataAsUShort();
+
+ QPointF margins(2, 2);
+ QPointF texMargins = margins / m_glyph_cache->fontScale();
+
+ for (int i = 0; i < glyphIndexes.size(); ++i) {
+ quint32 glyphIndex = glyphIndexes.at(i);
+ QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex);
+ QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex);
+
+ if (!metrics.isNull() && !c.isNull()) {
+ metrics.width += margins.x() * 2;
+ metrics.height += margins.y() * 2;
+ metrics.baselineX -= margins.x();
+ metrics.baselineY += margins.y();
+ c.xMargin -= texMargins.x();
+ c.yMargin -= texMargins.y();
+ c.width += texMargins.x() * 2;
+ c.height += texMargins.y() * 2;
+ }
+
+ QPointF glyphPosition = m_glyphs.positions().at(i) + m_position;
+ qreal x = glyphPosition.x() + metrics.baselineX;
+ qreal y = glyphPosition.y() - metrics.baselineY;
+
+ boundingRect |= QRectF(x, y, metrics.width, metrics.height);
+
+ float cx1 = x;
+ float cx2 = x + metrics.width;
+ float cy1 = y;
+ float cy2 = y + metrics.height;
+
+ float tx1 = c.x + c.xMargin;
+ float tx2 = tx1 + c.width;
+ float ty1 = c.y + c.yMargin;
+ float ty2 = ty1 + c.height;
+
+ if (m_baseLine.isNull())
+ m_baseLine = glyphPosition;
+
+ int vi = i & 1 ? (glyphIndexes.size() + 1) / 2 + i / 2 : i / 2;
+ vp[4 * vi + 0] = QVector4D(cx1, cy1, tx1, ty1);
+ vp[4 * vi + 1] = QVector4D(cx2, cy1, tx2, ty1);
+ vp[4 * vi + 2] = QVector4D(cx1, cy2, tx1, ty2);
+ vp[4 * vi + 3] = QVector4D(cx2, cy2, tx2, ty2);
+
+ int o = i * 4;
+ ip[6 * i + 0] = o + 0;
+ ip[6 * i + 1] = o + 2;
+ ip[6 * i + 2] = o + 3;
+ ip[6 * i + 3] = o + 3;
+ ip[6 * i + 4] = o + 1;
+ ip[6 * i + 5] = o + 0;
+ }
+
+ setBoundingRect(boundingRect);
+ markDirty(DirtyGeometry);
+}
+
+void QSGDistanceFieldGlyphNode::updateFont()
+{
+ m_glyph_cache = QSGDistanceFieldGlyphCache::get(QGLContext::currentContext(), m_glyphs.font());
+}
+
+void QSGDistanceFieldGlyphNode::updateMaterial()
+{
+ delete m_material;
+
+ if (m_style == QSGText::Normal) {
+ if (m_antialiasingMode == SubPixelAntialiasing)
+ m_material = new QSGSubPixelDistanceFieldTextMaterial;
+ else
+ m_material = new QSGDistanceFieldTextMaterial;
+ } else {
+ QSGDistanceFieldStyledTextMaterial *material;
+ if (m_style == QSGText::Outline) {
+ material = new QSGDistanceFieldOutlineTextMaterial;
+ } else {
+ QSGDistanceFieldShiftedStyleTextMaterial *sMaterial = new QSGDistanceFieldShiftedStyleTextMaterial;
+ if (m_style == QSGText::Raised)
+ sMaterial->setShift(QPointF(0.0, 1.0));
+ else
+ sMaterial->setShift(QPointF(0.0, -1.0));
+ material = sMaterial;
+ }
+ material->setStyleColor(m_styleColor);
+ m_material = material;
+ }
+
+ m_material->setGlyphCache(m_glyph_cache);
+ m_material->setColor(m_color);
+ setMaterial(m_material);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp
new file mode 100644
index 0000000000..e332434138
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -0,0 +1,656 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdistancefieldglyphnode_p_p.h"
+#include "qsgdistancefieldglyphcache_p.h"
+#include <private/qsgtexture_p.h>
+#include <QtOpenGL/qglfunctions.h>
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGDistanceFieldTextMaterialShader : public QSGMaterialShader
+{
+public:
+ QSGDistanceFieldTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+protected:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ void updateAlphaRange();
+
+ qreal m_fontScale;
+ qreal m_matrixScale;
+
+ int m_matrix_id;
+ int m_textureScale_id;
+ int m_alphaMin_id;
+ int m_alphaMax_id;
+ int m_color_id;
+};
+
+const char *QSGDistanceFieldTextMaterialShader::vertexShader() const {
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *QSGDistanceFieldTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "void main() { \n"
+ " gl_FragColor = color * smoothstep(alphaMin, \n"
+ " alphaMax, \n"
+ " texture2D(texture, sampleCoord).a); \n"
+ "}";
+}
+
+char const *const *QSGDistanceFieldTextMaterialShader::attributeNames() const {
+ static char const *const attr[] = { "vCoord", "tCoord", 0 };
+ return attr;
+}
+
+QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader()
+ : m_fontScale(1.0)
+ , m_matrixScale(1.0)
+{
+}
+
+void QSGDistanceFieldTextMaterialShader::updateAlphaRange()
+{
+ qreal combinedScale = m_fontScale * m_matrixScale;
+ qreal alphaMin = qMax(0.0, 0.5 - 0.07 / combinedScale);
+ qreal alphaMax = qMin(0.5 + 0.07 / combinedScale, 1.0);
+ m_program.setUniformValue(m_alphaMin_id, GLfloat(alphaMin));
+ m_program.setUniformValue(m_alphaMax_id, GLfloat(alphaMax));
+}
+
+void QSGDistanceFieldTextMaterialShader::initialize()
+{
+ QSGMaterialShader::initialize();
+ m_matrix_id = m_program.uniformLocation("matrix");
+ m_textureScale_id = m_program.uniformLocation("textureScale");
+ m_color_id = m_program.uniformLocation("color");
+ m_alphaMin_id = m_program.uniformLocation("alphaMin");
+ m_alphaMax_id = m_program.uniformLocation("alphaMax");
+}
+
+void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect);
+ QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
+
+ bool updated = material->updateTexture();
+ if (updated && !material->glyphCache()->useWorkaroundBrokenFBOReadback())
+ activate();
+
+ if (oldMaterial == 0
+ || material->color() != oldMaterial->color()
+ || state.isOpacityDirty()) {
+ QVector4D color(material->color().redF(), material->color().greenF(),
+ material->color().blueF(), material->color().alphaF());
+ color *= state.opacity();
+ m_program.setUniformValue(m_color_id, color);
+ }
+
+ bool updateRange = false;
+ if (oldMaterial == 0
+ || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale()) {
+ m_fontScale = material->glyphCache()->fontScale();
+ updateRange = true;
+ }
+ if (state.isMatrixDirty()) {
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+ m_matrixScale = qSqrt(state.modelViewMatrix().determinant());
+ updateRange = true;
+ }
+ if (updateRange)
+ updateAlphaRange();
+
+ Q_ASSERT(material->glyphCache());
+
+ if (updated
+ || oldMaterial == 0
+ || oldMaterial->glyphCache()->texture() != material->glyphCache()->texture()) {
+ m_program.setUniformValue(m_textureScale_id, QVector2D(1.0 / material->glyphCache()->textureSize().width(),
+ 1.0 / material->glyphCache()->textureSize().height()));
+ glBindTexture(GL_TEXTURE_2D, material->glyphCache()->texture());
+
+ if (updated) {
+ // Set the mag/min filters to be linear. We only need to do this when the texture
+ // has been recreated.
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+ }
+}
+
+QSGDistanceFieldTextMaterial::QSGDistanceFieldTextMaterial()
+ : m_glyph_cache(0)
+{
+ setFlag(Blending, true);
+}
+
+QSGDistanceFieldTextMaterial::~QSGDistanceFieldTextMaterial()
+{
+}
+
+QSGMaterialType *QSGDistanceFieldTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader() const
+{
+ return new QSGDistanceFieldTextMaterialShader;
+}
+
+bool QSGDistanceFieldTextMaterial::updateTexture()
+{
+ m_glyph_cache->updateCache();
+ QSize glyphCacheSize = m_glyph_cache->textureSize();
+ if (glyphCacheSize != m_size) {
+ m_size = glyphCacheSize;
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int QSGDistanceFieldTextMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGDistanceFieldTextMaterial *other = static_cast<const QSGDistanceFieldTextMaterial *>(o);
+ if (m_glyph_cache->fontScale() != other->m_glyph_cache->fontScale()) {
+ qreal s1 = m_glyph_cache->fontScale();
+ qreal s2 = other->m_glyph_cache->fontScale();
+ return int(s2 < s1) - int(s1 < s2);
+ }
+ QRgb c1 = m_color.rgba();
+ QRgb c2 = other->m_color.rgba();
+ return int(c2 < c1) - int(c1 < c2);
+}
+
+
+class DistanceFieldStyledTextMaterialShader : public QSGDistanceFieldTextMaterialShader
+{
+public:
+ DistanceFieldStyledTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual void initialize();
+ virtual const char *fragmentShader() const = 0;
+
+ int m_styleColor_id;
+};
+
+DistanceFieldStyledTextMaterialShader::DistanceFieldStyledTextMaterialShader()
+ : QSGDistanceFieldTextMaterialShader()
+{
+}
+
+void DistanceFieldStyledTextMaterialShader::initialize()
+{
+ QSGDistanceFieldTextMaterialShader::initialize();
+ m_styleColor_id = m_program.uniformLocation("styleColor");
+}
+
+void DistanceFieldStyledTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ QSGDistanceFieldTextMaterialShader::updateState(state, newEffect, oldEffect);
+
+ QSGDistanceFieldStyledTextMaterial *material = static_cast<QSGDistanceFieldStyledTextMaterial *>(newEffect);
+ QSGDistanceFieldStyledTextMaterial *oldMaterial = static_cast<QSGDistanceFieldStyledTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0
+ || material->styleColor() != oldMaterial->styleColor()
+ || (state.isOpacityDirty())) {
+ QVector4D color(material->styleColor().redF(), material->styleColor().greenF(),
+ material->styleColor().blueF(), material->styleColor().alphaF());
+ color *= state.opacity();
+ m_program.setUniformValue(m_styleColor_id, color);
+ }
+}
+
+QSGDistanceFieldStyledTextMaterial::QSGDistanceFieldStyledTextMaterial()
+ : QSGDistanceFieldTextMaterial()
+{
+}
+
+QSGDistanceFieldStyledTextMaterial::~QSGDistanceFieldStyledTextMaterial()
+{
+}
+
+int QSGDistanceFieldStyledTextMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGDistanceFieldStyledTextMaterial *other = static_cast<const QSGDistanceFieldStyledTextMaterial *>(o);
+ if (m_styleColor != other->m_styleColor) {
+ QRgb c1 = m_styleColor.rgba();
+ QRgb c2 = other->m_styleColor.rgba();
+ return int(c2 < c1) - int(c1 < c2);
+ }
+ return QSGDistanceFieldTextMaterial::compare(o);
+}
+
+
+class DistanceFieldOutlineTextMaterialShader : public DistanceFieldStyledTextMaterialShader
+{
+public:
+ DistanceFieldOutlineTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual void initialize();
+ virtual const char *fragmentShader() const;
+
+ void updateOutlineAlphaRange(int dfRadius);
+
+ int m_outlineAlphaMax0_id;
+ int m_outlineAlphaMax1_id;
+};
+
+const char *DistanceFieldOutlineTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform lowp vec4 styleColor; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "uniform highp float outlineAlphaMax0; \n"
+ "uniform highp float outlineAlphaMax1; \n"
+ "void main() { \n"
+ " mediump float d = texture2D(texture, sampleCoord).a; \n"
+ " gl_FragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d)) \n"
+ " * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d); \n"
+ "}";
+}
+
+DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader()
+ : DistanceFieldStyledTextMaterialShader()
+{
+}
+
+void DistanceFieldOutlineTextMaterialShader::initialize()
+{
+ DistanceFieldStyledTextMaterialShader::initialize();
+ m_outlineAlphaMax0_id = m_program.uniformLocation("outlineAlphaMax0");
+ m_outlineAlphaMax1_id = m_program.uniformLocation("outlineAlphaMax1");
+}
+
+void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(int dfRadius)
+{
+ qreal outlineLimit = qMax(qreal(0.2), qreal(0.5 - 0.5 / dfRadius / m_fontScale));
+
+ qreal combinedScale = m_fontScale * m_matrixScale;
+ qreal alphaMin = qMax(0.0, 0.5 - 0.07 / combinedScale);
+ qreal styleAlphaMin0 = qMax(0.0, outlineLimit - 0.07 / combinedScale);
+ qreal styleAlphaMin1 = qMin(qreal(outlineLimit + 0.07 / combinedScale), alphaMin);
+ m_program.setUniformValue(m_outlineAlphaMax0_id, GLfloat(styleAlphaMin0));
+ m_program.setUniformValue(m_outlineAlphaMax1_id, GLfloat(styleAlphaMin1));
+}
+
+void DistanceFieldOutlineTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ DistanceFieldStyledTextMaterialShader::updateState(state, newEffect, oldEffect);
+
+ QSGDistanceFieldOutlineTextMaterial *material = static_cast<QSGDistanceFieldOutlineTextMaterial *>(newEffect);
+ QSGDistanceFieldOutlineTextMaterial *oldMaterial = static_cast<QSGDistanceFieldOutlineTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0
+ || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale()
+ || state.isMatrixDirty())
+ updateOutlineAlphaRange(material->glyphCache()->distanceFieldRadius());
+}
+
+
+QSGDistanceFieldOutlineTextMaterial::QSGDistanceFieldOutlineTextMaterial()
+ : QSGDistanceFieldStyledTextMaterial()
+{
+}
+
+QSGDistanceFieldOutlineTextMaterial::~QSGDistanceFieldOutlineTextMaterial()
+{
+}
+
+QSGMaterialType *QSGDistanceFieldOutlineTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGDistanceFieldOutlineTextMaterial::createShader() const
+{
+ return new DistanceFieldOutlineTextMaterialShader;
+}
+
+
+class DistanceFieldShiftedStyleTextMaterialShader : public DistanceFieldStyledTextMaterialShader
+{
+public:
+ DistanceFieldShiftedStyleTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ void updateShift(const QSGDistanceFieldGlyphCache *cache, const QPointF& shift);
+
+ int m_shift_id;
+};
+
+DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader()
+ : DistanceFieldStyledTextMaterialShader()
+{
+}
+
+void DistanceFieldShiftedStyleTextMaterialShader::initialize()
+{
+ DistanceFieldStyledTextMaterialShader::initialize();
+ m_shift_id = m_program.uniformLocation("shift");
+}
+
+void DistanceFieldShiftedStyleTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ DistanceFieldStyledTextMaterialShader::updateState(state, newEffect, oldEffect);
+
+ QSGDistanceFieldShiftedStyleTextMaterial *material = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(newEffect);
+ QSGDistanceFieldShiftedStyleTextMaterial *oldMaterial = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0
+ || oldMaterial->glyphCache()->fontScale() != material->glyphCache()->fontScale()
+ || oldMaterial->shift() != material->shift()
+ || oldMaterial->glyphCache()->textureSize() != material->glyphCache()->textureSize()) {
+ updateShift(material->glyphCache(), material->shift());
+ }
+}
+
+void DistanceFieldShiftedStyleTextMaterialShader::updateShift(const QSGDistanceFieldGlyphCache *cache, const QPointF &shift)
+{
+ QPointF texel(1.0 / cache->fontScale() * shift.x(),
+ 1.0 / cache->fontScale() * shift.y());
+ m_program.setUniformValue(m_shift_id, texel);
+}
+
+const char *DistanceFieldShiftedStyleTextMaterialShader::vertexShader() const
+{
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "uniform highp vec2 shift; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec2 shiftedSampleCoord; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " shiftedSampleCoord = (tCoord - shift) * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *DistanceFieldShiftedStyleTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec2 shiftedSampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform lowp vec4 styleColor; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "void main() { \n"
+ " highp float a = smoothstep(alphaMin, alphaMax, texture2D(texture, sampleCoord).a);\n"
+ " highp vec4 shifted = styleColor * smoothstep(alphaMin, \n"
+ " alphaMax, \n"
+ " texture2D(texture, shiftedSampleCoord).a); \n"
+ " gl_FragColor = mix(shifted, color, a); \n"
+ "}";
+}
+
+QSGDistanceFieldShiftedStyleTextMaterial::QSGDistanceFieldShiftedStyleTextMaterial()
+ : QSGDistanceFieldStyledTextMaterial()
+{
+}
+
+QSGDistanceFieldShiftedStyleTextMaterial::~QSGDistanceFieldShiftedStyleTextMaterial()
+{
+}
+
+QSGMaterialType *QSGDistanceFieldShiftedStyleTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGDistanceFieldShiftedStyleTextMaterial::createShader() const
+{
+ return new DistanceFieldShiftedStyleTextMaterialShader;
+}
+
+
+class QSGSubPixelDistanceFieldTextMaterialShader : public QSGDistanceFieldTextMaterialShader
+{
+public:
+ virtual void initialize();
+ virtual void activate();
+ virtual void deactivate();
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+private:
+ int m_fontScale_id;
+ int m_vecDelta_id;
+};
+
+const char *QSGSubPixelDistanceFieldTextMaterialShader::vertexShader() const {
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "uniform highp float fontScale; \n"
+ "uniform highp vec4 vecDelta; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec3 sampleFarLeft; \n"
+ "varying highp vec3 sampleNearLeft; \n"
+ "varying highp vec3 sampleNearRight; \n"
+ "varying highp vec3 sampleFarRight; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ // Calculate neighbour pixel position in item space.
+ " highp vec3 wDelta = gl_Position.w * vecDelta.xyw; \n"
+ " highp vec3 farLeft = vCoord.xyw - 0.667 * wDelta; \n"
+ " highp vec3 nearLeft = vCoord.xyw - 0.333 * wDelta; \n"
+ " highp vec3 nearRight = vCoord.xyw + 0.333 * wDelta; \n"
+ " highp vec3 farRight = vCoord.xyw + 0.667 * wDelta; \n"
+ // Calculate neighbour texture coordinate.
+ " highp vec2 scale = textureScale / fontScale; \n"
+ " highp vec2 base = sampleCoord - scale * vCoord.xy; \n"
+ " sampleFarLeft = vec3(base * farLeft.z + scale * farLeft.xy, farLeft.z); \n"
+ " sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z); \n"
+ " sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z); \n"
+ " sampleFarRight = vec3(base * farRight.z + scale * farRight.xy, farRight.z); \n"
+ "}";
+}
+
+const char *QSGSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec3 sampleFarLeft; \n"
+ "varying highp vec3 sampleNearLeft; \n"
+ "varying highp vec3 sampleNearRight; \n"
+ "varying highp vec3 sampleFarRight; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "void main() { \n"
+ " highp vec4 n; \n"
+ " n.x = texture2DProj(texture, sampleFarLeft).a; \n"
+ " n.y = texture2DProj(texture, sampleNearLeft).a; \n"
+ " highp float c = texture2D(texture, sampleCoord).a; \n"
+ " n.z = texture2DProj(texture, sampleNearRight).a; \n"
+ " n.w = texture2DProj(texture, sampleFarRight).a; \n"
+#if 0
+ // Blurrier, faster.
+ " n = smoothstep(alphaMin, alphaMax, n); \n"
+ " c = smoothstep(alphaMin, alphaMax, c); \n"
+#else
+ // Sharper, slower.
+ " highp vec2 d = min(abs(n.yw - n.xz) * 2., 0.67); \n"
+ " highp vec2 lo = mix(vec2(alphaMin), vec2(0.5), d); \n"
+ " highp vec2 hi = mix(vec2(alphaMax), vec2(0.5), d); \n"
+ " n = smoothstep(lo.xxyy, hi.xxyy, n); \n"
+ " c = smoothstep(lo.x + lo.y, hi.x + hi.y, 2. * c); \n"
+#endif
+ " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
+ "}";
+}
+
+//const char *QSGSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
+// return
+// "#extension GL_OES_standard_derivatives: enable \n"
+// "varying highp vec2 sampleCoord; \n"
+// "uniform sampler2D texture; \n"
+// "uniform lowp vec4 color; \n"
+// "uniform highp float alphaMin; \n"
+// "uniform highp float alphaMax; \n"
+// "void main() { \n"
+// " highp vec2 delta = dFdx(sampleCoord); \n"
+// " highp vec4 n; \n"
+// " n.x = texture2D(texture, sampleCoord - 0.667 * delta).a; \n"
+// " n.y = texture2D(texture, sampleCoord - 0.333 * delta).a; \n"
+// " highp float c = texture2D(texture, sampleCoord).a; \n"
+// " n.z = texture2D(texture, sampleCoord + 0.333 * delta).a; \n"
+// " n.w = texture2D(texture, sampleCoord + 0.667 * delta).a; \n"
+// " n = smoothstep(alphaMin, alphaMax, n); \n"
+// " c = smoothstep(alphaMin, alphaMax, c); \n"
+// " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
+// "}";
+//}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::initialize()
+{
+ QSGDistanceFieldTextMaterialShader::initialize();
+ m_fontScale_id = m_program.uniformLocation("fontScale");
+ m_vecDelta_id = m_program.uniformLocation("vecDelta");
+}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::activate()
+{
+ QSGDistanceFieldTextMaterialShader::activate();
+ glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
+}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::deactivate()
+{
+ QSGDistanceFieldTextMaterialShader::deactivate();
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect);
+ QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0 || material->color() != oldMaterial->color()) {
+ QColor c = material->color();
+ state.context()->functions()->glBlendColor(c.redF(), c.greenF(), c.blueF(), 1.0f);
+ }
+
+ if (oldMaterial == 0 || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale())
+ m_program.setUniformValue(m_fontScale_id, GLfloat(material->glyphCache()->fontScale()));
+
+ if (oldMaterial == 0 || state.isMatrixDirty()) {
+ int viewportWidth = state.viewportRect().width();
+ QMatrix4x4 mat = state.combinedMatrix().inverted();
+ m_program.setUniformValue(m_vecDelta_id, mat.column(0) * (qreal(2) / viewportWidth));
+ }
+
+ QSGDistanceFieldTextMaterialShader::updateState(state, newEffect, oldEffect);
+}
+
+QSGMaterialType *QSGSubPixelDistanceFieldTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGSubPixelDistanceFieldTextMaterial::createShader() const
+{
+ return new QSGSubPixelDistanceFieldTextMaterialShader;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h
new file mode 100644
index 0000000000..d42f187af3
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DISTANCEFIELD_GLYPHNODE_H
+#define DISTANCEFIELD_GLYPHNODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+#include "qsgtexture.h"
+#include <qsgtext_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGDistanceFieldGlyphCache;
+class QSGDistanceFieldTextMaterial;
+class QSGDistanceFieldGlyphNode: public QSGGlyphNode
+{
+public:
+ QSGDistanceFieldGlyphNode();
+ ~QSGDistanceFieldGlyphNode();
+
+ virtual QPointF baseLine() const { return m_baseLine; }
+ virtual void setGlyphs(const QPointF &position, const QGlyphs &glyphs);
+ virtual void setColor(const QColor &color);
+
+ virtual void setPreferredAntialiasingMode(AntialiasingMode mode);
+
+ void setStyle(QSGText::TextStyle style);
+ void setStyleColor(const QColor &color);
+
+private:
+ void updateGeometry();
+ void updateFont();
+ void updateMaterial();
+
+ QColor m_color;
+ QPointF m_baseLine;
+ QSGDistanceFieldTextMaterial *m_material;
+ QPointF m_position;
+ QGlyphs m_glyphs;
+ QSGDistanceFieldGlyphCache *m_glyph_cache;
+ QSGGeometry m_geometry;
+ QSGText::TextStyle m_style;
+ QColor m_styleColor;
+ AntialiasingMode m_antialiasingMode;
+};
+
+QT_END_HEADER
+
+QT_END_NAMESPACE
+
+#endif // DISTANCEFIELD_GLYPHNODE_H
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h
new file mode 100644
index 0000000000..37415e5dae
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DISTANCEFIELDTEXTMATERIAL_H
+#define DISTANCEFIELDTEXTMATERIAL_H
+
+#include <qsgmaterial.h>
+#include "qsgdistancefieldglyphnode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGDistanceFieldGlyphCache;
+
+class QSGDistanceFieldTextMaterial: public QSGMaterial
+{
+public:
+ QSGDistanceFieldTextMaterial();
+ ~QSGDistanceFieldTextMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setColor(const QColor &color) { m_color = color; }
+ const QColor &color() const { return m_color; }
+
+ void setGlyphCache(QSGDistanceFieldGlyphCache *a) { m_glyph_cache = a; }
+ QSGDistanceFieldGlyphCache *glyphCache() const { return m_glyph_cache; }
+
+ bool updateTexture();
+
+protected:
+ QSize m_size;
+ QColor m_color;
+ QSGDistanceFieldGlyphCache *m_glyph_cache;
+};
+
+class QSGDistanceFieldStyledTextMaterial : public QSGDistanceFieldTextMaterial
+{
+public:
+ QSGDistanceFieldStyledTextMaterial();
+ ~QSGDistanceFieldStyledTextMaterial();
+
+ virtual QSGMaterialType *type() const = 0;
+ virtual QSGMaterialShader *createShader() const = 0;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setStyleColor(const QColor &color) { m_styleColor = color; }
+ const QColor &styleColor() const { return m_styleColor; }
+
+protected:
+ QColor m_styleColor;
+};
+
+class QSGDistanceFieldOutlineTextMaterial : public QSGDistanceFieldStyledTextMaterial
+{
+public:
+ QSGDistanceFieldOutlineTextMaterial();
+ ~QSGDistanceFieldOutlineTextMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+};
+
+class QSGDistanceFieldShiftedStyleTextMaterial : public QSGDistanceFieldStyledTextMaterial
+{
+public:
+ QSGDistanceFieldShiftedStyleTextMaterial();
+ ~QSGDistanceFieldShiftedStyleTextMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+
+ void setShift(const QPointF &shift) { m_shift = shift; }
+ const QPointF &shift() const { return m_shift; }
+
+protected:
+ QPointF m_shift;
+};
+
+class QSGSubPixelDistanceFieldTextMaterial : public QSGDistanceFieldTextMaterial
+{
+public:
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // DISTANCEFIELDTEXTMATERIAL_H
diff --git a/src/declarative/scenegraph/qsgflashnode.cpp b/src/declarative/scenegraph/qsgflashnode.cpp
new file mode 100644
index 0000000000..c2c1919f82
--- /dev/null
+++ b/src/declarative/scenegraph/qsgflashnode.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**Ëš
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgflashnode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGFlashNode::QSGFlashNode()
+ : m_counter(1)
+{
+ setFlag(UsePreprocess);
+ setColor(QColor(rand()%56 + 200, rand()%56 + 200, rand()%156 + 100)); // A random, mostly yellow, color
+}
+
+void QSGFlashNode::preprocess()
+{
+ if (m_counter) {
+ --m_counter;
+ } else {
+ delete this;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgflashnode_p.h b/src/declarative/scenegraph/qsgflashnode_p.h
new file mode 100644
index 0000000000..776ae48f13
--- /dev/null
+++ b/src/declarative/scenegraph/qsgflashnode_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**Ëš
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFLASHNODE_H
+#define QSGFLASHNODE_H
+
+#include <QSGSimpleRectNode>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGFlashNode : public QSGSimpleRectNode
+{
+public:
+ QSGFlashNode();
+
+ void preprocess();
+
+private:
+ int m_counter;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGFLASHNODE_H
+
diff --git a/src/declarative/scenegraph/scenegraph.pri b/src/declarative/scenegraph/scenegraph.pri
new file mode 100644
index 0000000000..77a93e4811
--- /dev/null
+++ b/src/declarative/scenegraph/scenegraph.pri
@@ -0,0 +1,80 @@
+INCLUDEPATH += $$PWD/coreapi $$PWD/convenience $$PWD/3d
+!contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL
+
+QT += opengl
+
+
+# Core API
+HEADERS += \
+ $$PWD/coreapi/qsgdefaultrenderer_p.h \
+ $$PWD/coreapi/qsggeometry.h \
+ $$PWD/coreapi/qsgmaterial.h \
+ $$PWD/coreapi/qsgmatrix4x4stack.h \
+ $$PWD/coreapi/qsgmatrix4x4stack_p.h \
+ $$PWD/coreapi/qsgnode.h \
+ $$PWD/coreapi/qsgnodeupdater_p.h \
+ $$PWD/coreapi/qsgrenderer_p.h
+SOURCES += \
+ $$PWD/coreapi/qsgdefaultrenderer.cpp \
+ $$PWD/coreapi/qsggeometry.cpp \
+ $$PWD/coreapi/qsgmaterial.cpp \
+ $$PWD/coreapi/qsgmatrix4x4stack.cpp \
+ $$PWD/coreapi/qsgnode.cpp \
+ $$PWD/coreapi/qsgnodeupdater.cpp \
+ $$PWD/coreapi/qsgrenderer.cpp
+
+
+# Util API
+HEADERS += \
+ $$PWD/util/qsgareaallocator_p.h \
+ $$PWD/util/qsgengine.h \
+ $$PWD/util/qsgflatcolormaterial.h \
+ $$PWD/util/qsgsimplerectnode.h \
+ $$PWD/util/qsgsimpletexturenode.h \
+ $$PWD/util/qsgtexturematerial.h \
+ $$PWD/util/qsgtexturematerial_p.h \
+ $$PWD/util/qsgvertexcolormaterial_p.h \
+ $$PWD/util/qsgtexture.h \
+ $$PWD/util/qsgtexture_p.h \
+ $$PWD/util/qsgtextureprovider_p.h \
+ $$PWD/util/qsgpainternode_p.h
+
+SOURCES += \
+ $$PWD/util/qsgareaallocator.cpp \
+ $$PWD/util/qsgengine.cpp \
+ $$PWD/util/qsgflatcolormaterial.cpp \
+ $$PWD/util/qsgsimplerectnode.cpp \
+ $$PWD/util/qsgsimpletexturenode.cpp \
+ $$PWD/util/qsgtexturematerial.cpp \
+ $$PWD/util/qsgvertexcolormaterial.cpp \
+ $$PWD/util/qsgtexture.cpp \
+ $$PWD/util/qsgtextureprovider.cpp \
+ $$PWD/util/qsgpainternode.cpp
+
+
+# QML / Adaptations API
+HEADERS += \
+ $$PWD/qsgadaptationlayer_p.h \
+ $$PWD/qsgcontext_p.h \
+ $$PWD/qsgcontextplugin_p.h \
+ $$PWD/qsgdefaultglyphnode_p.h \
+ $$PWD/qsgdistancefieldglyphcache_p.h \
+ $$PWD/qsgdistancefieldglyphnode_p.h \
+ $$PWD/qsgdistancefieldglyphnode_p_p.h \
+ $$PWD/qsgdefaultglyphnode_p_p.h \
+ $$PWD/qsgdefaultimagenode_p.h \
+ $$PWD/qsgdefaultrectanglenode_p.h \
+ $$PWD/qsgflashnode_p.h
+
+SOURCES += \
+ $$PWD/qsgadaptationlayer.cpp \
+ $$PWD/qsgcontext.cpp \
+ $$PWD/qsgcontextplugin.cpp \
+ $$PWD/qsgdefaultglyphnode.cpp \
+ $$PWD/qsgdefaultglyphnode_p.cpp \
+ $$PWD/qsgdistancefieldglyphcache.cpp \
+ $$PWD/qsgdistancefieldglyphnode.cpp \
+ $$PWD/qsgdistancefieldglyphnode_p.cpp \
+ $$PWD/qsgdefaultimagenode.cpp \
+ $$PWD/qsgdefaultrectanglenode.cpp \
+ $$PWD/qsgflashnode.cpp
diff --git a/src/declarative/scenegraph/util/qsgareaallocator.cpp b/src/declarative/scenegraph/util/qsgareaallocator.cpp
new file mode 100644
index 0000000000..a28575c982
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgareaallocator.cpp
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgareaallocator_p.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qpoint.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+ enum SplitType
+ {
+ VerticalSplit,
+ HorizontalSplit
+ };
+
+ static const int maxMargin = 2;
+}
+
+struct QSGAreaAllocatorNode
+{
+ QSGAreaAllocatorNode(QSGAreaAllocatorNode *parent);
+ ~QSGAreaAllocatorNode();
+ inline bool isLeaf();
+
+ QSGAreaAllocatorNode *parent;
+ QSGAreaAllocatorNode *left;
+ QSGAreaAllocatorNode *right;
+ int split; // only valid for inner nodes.
+ SplitType splitType;
+ bool isOccupied; // only valid for leaf nodes.
+};
+
+QSGAreaAllocatorNode::QSGAreaAllocatorNode(QSGAreaAllocatorNode *parent)
+ : parent(parent)
+ , left(0)
+ , right(0)
+ , isOccupied(false)
+{
+}
+
+QSGAreaAllocatorNode::~QSGAreaAllocatorNode()
+{
+ delete left;
+ delete right;
+}
+
+bool QSGAreaAllocatorNode::isLeaf()
+{
+ Q_ASSERT((left != 0) == (right != 0));
+ return !left;
+}
+
+
+QSGAreaAllocator::QSGAreaAllocator(const QSize &size) : m_size(size)
+{
+ m_root = new QSGAreaAllocatorNode(0);
+}
+
+QSGAreaAllocator::~QSGAreaAllocator()
+{
+ delete m_root;
+}
+
+QRect QSGAreaAllocator::allocate(const QSize &size)
+{
+ QPoint point;
+ bool result = allocateInNode(size, point, QRect(QPoint(0, 0), m_size), m_root);
+ return result ? QRect(point, size) : QRect();
+}
+
+bool QSGAreaAllocator::deallocate(const QRect &rect)
+{
+ return deallocateInNode(rect.topLeft(), m_root);
+}
+
+bool QSGAreaAllocator::allocateInNode(const QSize &size, QPoint &result, const QRect &currentRect, QSGAreaAllocatorNode *node)
+{
+ if (size.width() > currentRect.width() || size.height() > currentRect.height())
+ return false;
+
+ if (node->isLeaf()) {
+ if (node->isOccupied)
+ return false;
+ if (size.width() + maxMargin >= currentRect.width() && size.height() + maxMargin >= currentRect.height()) {
+ //Snug fit, occupy entire rectangle.
+ node->isOccupied = true;
+ result = currentRect.topLeft();
+ return true;
+ }
+ // TODO: Reuse nodes.
+ // Split node.
+ node->left = new QSGAreaAllocatorNode(node);
+ node->right = new QSGAreaAllocatorNode(node);
+ QRect splitRect = currentRect;
+ if ((currentRect.width() - size.width()) * currentRect.height() < (currentRect.height() - size.height()) * currentRect.width()) {
+ node->splitType = HorizontalSplit;
+ node->split = currentRect.top() + size.height();
+ splitRect.setHeight(size.height());
+ } else {
+ node->splitType = VerticalSplit;
+ node->split = currentRect.left() + size.width();
+ splitRect.setWidth(size.width());
+ }
+ return allocateInNode(size, result, splitRect, node->left);
+ } else {
+ // TODO: avoid unnecessary recursion.
+ // has been split.
+ QRect leftRect = currentRect;
+ QRect rightRect = currentRect;
+ if (node->splitType == HorizontalSplit) {
+ leftRect.setHeight(node->split - leftRect.top());
+ rightRect.setTop(node->split);
+ } else {
+ leftRect.setWidth(node->split - leftRect.left());
+ rightRect.setLeft(node->split);
+ }
+ if (allocateInNode(size, result, leftRect, node->left))
+ return true;
+ if (allocateInNode(size, result, rightRect, node->right))
+ return true;
+ return false;
+ }
+}
+
+bool QSGAreaAllocator::deallocateInNode(const QPoint &pos, QSGAreaAllocatorNode *node)
+{
+ while (!node->isLeaf()) {
+ // has been split.
+ int cmp = node->splitType == HorizontalSplit ? pos.y() : pos.x();
+ node = cmp < node->split ? node->left : node->right;
+ }
+ if (!node->isOccupied)
+ return false;
+ node->isOccupied = false;
+ mergeNodeWithNeighbors(node);
+ return true;
+}
+
+void QSGAreaAllocator::mergeNodeWithNeighbors(QSGAreaAllocatorNode *node)
+{
+ bool done = false;
+ QSGAreaAllocatorNode *parent = 0;
+ QSGAreaAllocatorNode *current = 0;
+ QSGAreaAllocatorNode *sibling;
+ while (!done) {
+ Q_ASSERT(node->isLeaf());
+ Q_ASSERT(!node->isOccupied);
+ if (node->parent == 0)
+ return; // No neighbours.
+
+ SplitType splitType = SplitType(node->parent->splitType);
+ done = true;
+
+ /* Special case. Might be faster than going through the general code path.
+ // Merge with sibling.
+ parent = node->parent;
+ sibling = (node == parent->left ? parent->right : parent->left);
+ if (sibling->isLeaf() && !sibling->isOccupied) {
+ Q_ASSERT(!sibling->right);
+ node = parent;
+ parent->isOccupied = false;
+ delete parent->left;
+ delete parent->right;
+ parent->left = parent->right = 0;
+ done = false;
+ continue;
+ }
+ */
+
+ // Merge with left neighbour.
+ current = node;
+ parent = current->parent;
+ while (parent && current == parent->left && parent->splitType == splitType) {
+ current = parent;
+ parent = parent->parent;
+ }
+
+ if (parent && parent->splitType == splitType) {
+ Q_ASSERT(current == parent->right);
+ Q_ASSERT(parent->left);
+
+ QSGAreaAllocatorNode *neighbor = parent->left;
+ while (neighbor->right && neighbor->splitType == splitType)
+ neighbor = neighbor->right;
+
+ if (neighbor->isLeaf() && neighbor->parent->splitType == splitType && !neighbor->isOccupied) {
+ // Left neighbour can be merged.
+ parent->split = neighbor->parent->split;
+
+ parent = neighbor->parent;
+ sibling = neighbor == parent->left ? parent->right : parent->left;
+ QSGAreaAllocatorNode **nodeRef = &m_root;
+ if (parent->parent) {
+ if (parent == parent->parent->left)
+ nodeRef = &parent->parent->left;
+ else
+ nodeRef = &parent->parent->right;
+ }
+ sibling->parent = parent->parent;
+ *nodeRef = sibling;
+ parent->left = parent->right = 0;
+ delete parent;
+ delete neighbor;
+ done = false;
+ }
+ }
+
+ // Merge with right neighbour.
+ current = node;
+ parent = current->parent;
+ while (parent && current == parent->right && parent->splitType == splitType) {
+ current = parent;
+ parent = parent->parent;
+ }
+
+ if (parent && parent->splitType == splitType) {
+ Q_ASSERT(current == parent->left);
+ Q_ASSERT(parent->right);
+
+ QSGAreaAllocatorNode *neighbor = parent->right;
+ while (neighbor->left && neighbor->splitType == splitType)
+ neighbor = neighbor->left;
+
+ if (neighbor->isLeaf() && neighbor->parent->splitType == splitType && !neighbor->isOccupied) {
+ // Right neighbour can be merged.
+ parent->split = neighbor->parent->split;
+
+ parent = neighbor->parent;
+ sibling = neighbor == parent->left ? parent->right : parent->left;
+ QSGAreaAllocatorNode **nodeRef = &m_root;
+ if (parent->parent) {
+ if (parent == parent->parent->left)
+ nodeRef = &parent->parent->left;
+ else
+ nodeRef = &parent->parent->right;
+ }
+ sibling->parent = parent->parent;
+ *nodeRef = sibling;
+ parent->left = parent->right = 0;
+ delete parent;
+ delete neighbor;
+ done = false;
+ }
+ }
+ } // end while(!done)
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgareaallocator_p.h b/src/declarative/scenegraph/util/qsgareaallocator_p.h
new file mode 100644
index 0000000000..f84732fbdb
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgareaallocator_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef AREAALLOCATOR_H
+#define AREAALLOCATOR_H
+
+#include <QtCore/qsize.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRect;
+class QPoint;
+struct QSGAreaAllocatorNode;
+class Q_DECLARATIVE_EXPORT QSGAreaAllocator
+{
+public:
+ QSGAreaAllocator(const QSize &size);
+ ~QSGAreaAllocator();
+
+ QRect allocate(const QSize &size);
+ bool deallocate(const QRect &rect);
+ bool isEmpty() const { return m_root == 0; }
+ QSize size() const { return m_size; }
+private:
+ bool allocateInNode(const QSize &size, QPoint &result, const QRect &currentRect, QSGAreaAllocatorNode *node);
+ bool deallocateInNode(const QPoint &pos, QSGAreaAllocatorNode *node);
+ void mergeNodeWithNeighbors(QSGAreaAllocatorNode *node);
+
+ QSGAreaAllocatorNode *m_root;
+ QSize m_size;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/scenegraph/util/qsgengine.cpp b/src/declarative/scenegraph/util/qsgengine.cpp
new file mode 100644
index 0000000000..1b7f05809b
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgengine.cpp
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgengine.h"
+
+#include <private/qsgtexture_p.h>
+#include <private/qsgrenderer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGEnginePrivate : public QObjectPrivate
+{
+public:
+ QSGEnginePrivate()
+ : context(0)
+ , clearBeforeRender(true)
+ {
+ }
+
+ QSGContext *context;
+
+ bool clearBeforeRender;
+};
+
+
+/*!
+ \class QSGEngine
+ \brief The QSGEngine class serves as a generic entry point into scene graph specific APIs.
+
+ The QSGEngine class provides factory functions for creating textures. Though the user
+ can implement any type of texture using the abstract QSGTexture class, the QSGEngine
+ class provides some convenience for the default usecases. This also allows the scene
+ graph to apply hardware specific optimzations.
+
+ */
+
+
+
+/*!
+ Constructs a new QSGengine
+ */
+QSGEngine::QSGEngine(QObject *parent) :
+ QObject(*(new QSGEnginePrivate), parent)
+{
+}
+
+
+QSGEngine::~QSGEngine()
+{
+}
+
+/*!
+ \enum TextureOption
+
+ The TextureOption enums are used to customize a texture is wrapped.
+
+ \value TextureHasAlphaChannel The texture has an alpha channel and should
+ be drawn using blending.
+
+ \value TextureHasMipmaps The texture has mipmaps and can be drawn with
+ mipmapping enabled.
+
+ \value TextureOwnsGLTexture The texture object owns the texture id and
+ will delete the GL texture when the texture object is deleted.
+
+ */
+
+/*!
+ \fn void QSGEngine::beforeRendering()
+
+ This signal is emitted before the scene starts rendering.
+
+ Combined with the modes for clearing the background, this option
+ can be used to paint using raw GL under QML content.
+
+ The GL context used for rendering the scene graph will be bound
+ at this point.
+*/
+
+/*!
+ \fn void QSGEngine::afterRendering()
+
+ This signal is emitted after the scene has completed rendering, before swapbuffers is called.
+
+ This signal can be used to paint using raw GL on top of QML content,
+ or to do screen scraping of the current frame buffer.
+
+ The GL context used for rendering the scene graph will be bound at this point.
+ */
+
+
+
+/*!
+ Sets weither the scene graph rendering of QML should clear the color buffer
+ before it starts rendering to \a enbled.
+
+ By disabling clearing of the color buffer, it is possible to do GL painting
+ under the scene graph.
+
+ The color buffer is cleared by default.
+ */
+
+void QSGEngine::setClearBeforeRendering(bool enabled)
+{
+ Q_D(QSGEngine);
+ d->clearBeforeRender = enabled;
+ if (d->clearBeforeRender) {
+ d->context->renderer()->setClearMode(QSGRenderer::ClearDepthBuffer
+ | QSGRenderer::ClearColorBuffer);
+ } else {
+ d->context->renderer()->setClearMode(QSGRenderer::ClearDepthBuffer);
+ }
+}
+
+
+
+/*!
+ Returns weither clearing of the color buffer is done before rendering or not.
+ */
+
+bool QSGEngine::clearBeforeRendering() const
+{
+ Q_D(const QSGEngine);
+ return d->clearBeforeRender;
+}
+
+
+
+/*!
+ Creates a new QSGTexture from the supplied \a image. If the image has an
+ alpha channel, the corresponding texture will have an alpha channel.
+
+ The caller of the function is responsible for deleting the returned texture.
+
+ The actual GL texture will be deleted when the texture object is deleted.
+ */
+
+QSGTexture *QSGEngine::createTextureFromImage(const QImage &image) const
+{
+ Q_D(const QSGEngine);
+ return d->context->createTexture(image);
+}
+
+
+
+/*!
+ Creates a new QSGTexture object from an existing GL texture \a id.
+
+ The caller of the function is responsible for deleting the returned texture.
+
+ Use \a options to customize the texture attributes.
+ */
+QSGTexture *QSGEngine::createTextureFromId(uint id, const QSize &size, TextureOptions options) const
+{
+ QSGPlainTexture *texture = new QSGPlainTexture();
+ texture->setTextureId(id);
+ texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+ texture->setHasMipmaps(options & TextureHasMipmaps);
+ texture->setOwnsTexture(options & TextureOwnsGLTexture);
+ texture->setTextureSize(size);
+ return texture;
+}
+
+
+
+/*!
+ \internal
+
+ Sets the scene graph context of this engine to context.
+
+ The context will be set by the QSGcontext::initialize() function,
+ as part of constructing the engine object.
+ */
+
+void QSGEngine::setContext(QSGContext *context)
+{
+ Q_D(QSGEngine);
+ d->context = context;
+}
+
+
+
+/*!
+ Sets the background color of the scene graph to \a color.
+
+ Changing the clear color has no effect when clearing before rendering is
+ disabled.
+ */
+
+void QSGEngine::setClearColor(const QColor &color)
+{
+ d_func()->context->renderer()->setClearColor(color);
+}
+
+
+
+/*!
+ Returns the background color of the scene graph
+ */
+
+QColor QSGEngine::clearColor() const
+{
+ return d_func()->context->renderer()->clearColor();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgengine.h b/src/declarative/scenegraph/util/qsgengine.h
new file mode 100644
index 0000000000..9e07f3530d
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgengine.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGENGINE_H
+#define QSGENGINE_H
+
+#include <QObject>
+
+#include <qsgtexture.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGEnginePrivate;
+
+class QSGContext;
+class Q_DECLARATIVE_EXPORT QSGEngine : public QObject
+{
+ Q_OBJECT
+
+ Q_DECLARE_PRIVATE(QSGEngine)
+
+public:
+
+ enum TextureOption {
+ TextureHasAlphaChannel = 0x0001,
+ TextureHasMipmaps = 0x0002,
+ TextureOwnsGLTexture = 0x0004
+ };
+ Q_DECLARE_FLAGS(TextureOptions, TextureOption)
+
+ QSGTexture *createTextureFromImage(const QImage &image) const;
+ QSGTexture *createTextureFromId(uint id, const QSize &size, TextureOptions options = TextureOption(0)) const;
+
+ void setClearBeforeRendering(bool enabled);
+ bool clearBeforeRendering() const;
+
+ void setClearColor(const QColor &color);
+ QColor clearColor() const;
+
+signals:
+ void beforeRendering();
+ void afterRendering();
+
+private:
+ QSGEngine(QObject *parent = 0);
+ ~QSGEngine();
+
+ friend class QSGContext;
+ friend class QSGContextPrivate;
+ void setContext(QSGContext *context);
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGENGINE_H
diff --git a/src/declarative/scenegraph/util/qsgflatcolormaterial.cpp b/src/declarative/scenegraph/util/qsgflatcolormaterial.cpp
new file mode 100644
index 0000000000..e348655e6b
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgflatcolormaterial.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgflatcolormaterial.h"
+
+#include <qglshaderprogram.h>
+
+QT_BEGIN_NAMESPACE
+
+class FlatColorMaterialShader : public QSGMaterialShader
+{
+public:
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+ static QSGMaterialType type;
+
+private:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ int m_matrix_id;
+ int m_color_id;
+};
+
+QSGMaterialType FlatColorMaterialShader::type;
+
+void FlatColorMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+
+ QSGFlatColorMaterial *oldMaterial = static_cast<QSGFlatColorMaterial *>(oldEffect);
+ QSGFlatColorMaterial *newMaterial = static_cast<QSGFlatColorMaterial *>(newEffect);
+
+ const QColor &c = newMaterial->color();
+
+ if (oldMaterial == 0 || c != oldMaterial->color() || state.isOpacityDirty()) {
+ float opacity = state.opacity();
+ QVector4D v(c.redF() * c.alphaF() * opacity,
+ c.greenF() * c.alphaF() * opacity,
+ c.blueF() * c.alphaF() * opacity,
+ c.alphaF() * opacity);
+ m_program.setUniformValue(m_color_id, v);
+ }
+
+ if (state.isMatrixDirty())
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+}
+
+char const *const *FlatColorMaterialShader::attributeNames() const
+{
+ static char const *const attr[] = { "vCoord", 0 };
+ return attr;
+}
+
+void FlatColorMaterialShader::initialize()
+{
+ m_matrix_id = m_program.uniformLocation("matrix");
+ m_color_id = m_program.uniformLocation("color");
+}
+
+const char *FlatColorMaterialShader::vertexShader() const {
+ return
+ "attribute highp vec4 vCoord; \n"
+ "uniform highp mat4 matrix; \n"
+ "void main() { \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *FlatColorMaterialShader::fragmentShader() const {
+ return
+ "uniform lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color; \n"
+ "}";
+}
+
+
+QSGFlatColorMaterial::QSGFlatColorMaterial() : m_color(QColor(255, 255, 255))
+{
+}
+
+void QSGFlatColorMaterial::setColor(const QColor &color)
+{
+ m_color = color;
+ setFlag(Blending, m_color.alpha() != 0xff);
+}
+
+
+QSGMaterialType *QSGFlatColorMaterial::type() const
+{
+ return &FlatColorMaterialShader::type;
+}
+
+QSGMaterialShader *QSGFlatColorMaterial::createShader() const
+{
+ return new FlatColorMaterialShader;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgflatcolormaterial.h b/src/declarative/scenegraph/util/qsgflatcolormaterial.h
new file mode 100644
index 0000000000..d9a8d5973c
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgflatcolormaterial.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FLATCOLORMATERIAL_H
+#define FLATCOLORMATERIAL_H
+
+#include <qsgmaterial.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QSGFlatColorMaterial : public QSGMaterial
+{
+public:
+ QSGFlatColorMaterial();
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+
+ void setColor(const QColor &color);
+ const QColor &color() const { return m_color; }
+
+private:
+ QColor m_color;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // FLATCOLORMATERIAL_H
diff --git a/src/declarative/scenegraph/util/qsgpainternode.cpp b/src/declarative/scenegraph/util/qsgpainternode.cpp
new file mode 100644
index 0000000000..c7386d2fb9
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgpainternode.cpp
@@ -0,0 +1,379 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpainternode_p.h"
+
+#include "qsgpainteditem.h"
+#include <private/qsgcontext_p.h>
+#include <qglframebufferobject.h>
+#include <qglfunctions.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QT_MINIMUM_FBO_SIZE 64
+
+static inline int qt_next_power_of_two(int v)
+{
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ ++v;
+ return v;
+}
+
+QSGPainterTexture::QSGPainterTexture()
+ : QSGPlainTexture()
+{
+
+}
+
+void QSGPainterTexture::bind()
+{
+ if (m_dirty_rect.isNull() || m_texture_id == 0) {
+ QSGPlainTexture::bind();
+ } else {
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+
+ QImage subImage = m_image.copy(m_dirty_rect);
+
+ int w = m_dirty_rect.width();
+ int h = m_dirty_rect.height();
+ int y = m_image.height() - m_dirty_rect.y() - h;
+
+#ifdef QT_OPENGL_ES
+ for (int i = 0; i < h; ++i) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), y + i, w, 1,
+ GL_RGBA, GL_UNSIGNED_BYTE, subImage.constScanLine(h - 1 - i));
+ }
+#else
+ for (int i = 0; i < h; ++i) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), y + i, w, 1,
+ GL_BGRA, GL_UNSIGNED_BYTE, subImage.constScanLine(h - 1 - i));
+ }
+
+#endif
+
+ m_dirty_texture = false;
+ m_dirty_bind_options = false;
+ }
+ m_dirty_rect = QRect();
+}
+
+QSGPainterNode::QSGPainterNode(QSGPaintedItem *item)
+ : QSGGeometryNode()
+ , m_preferredRenderTarget(QSGPaintedItem::Image)
+ , m_actualRenderTarget(QSGPaintedItem::Image)
+ , m_item(item)
+ , m_fbo(0)
+ , m_multisampledFbo(0)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+ , m_texture(0)
+ , m_size(1, 1)
+ , m_dirtyContents(false)
+ , m_opaquePainting(false)
+ , m_linear_filtering(false)
+ , m_smoothPainting(false)
+ , m_extensionsChecked(false)
+ , m_multisamplingSupported(false)
+ , m_fillColor(Qt::transparent)
+ , m_dirtyGeometry(false)
+ , m_dirtyRenderTarget(false)
+ , m_dirtyTexture(false)
+{
+ setMaterial(&m_materialO);
+ setOpaqueMaterial(&m_material);
+ setGeometry(&m_geometry);
+ setFlag(UsePreprocess);
+}
+
+QSGPainterNode::~QSGPainterNode()
+{
+ delete m_texture;
+ delete m_fbo;
+ delete m_multisampledFbo;
+}
+
+void QSGPainterNode::preprocess()
+{
+ if (!m_dirtyContents)
+ return;
+
+ QRect dirtyRect = m_dirtyRect.isNull() ? QRect(0, 0, m_size.width(), m_size.height()) : m_dirtyRect;
+
+ QPainter painter;
+ if (m_actualRenderTarget == QSGPaintedItem::Image)
+ painter.begin(&m_image);
+ else if (m_multisampledFbo)
+ painter.begin(m_multisampledFbo);
+ else
+ painter.begin(m_fbo);
+
+ if (m_smoothPainting) {
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing
+ | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
+ }
+
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.fillRect(dirtyRect, m_fillColor);
+ painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+
+ if (!m_dirtyRect.isNull())
+ painter.setClipRect(dirtyRect);
+ m_item->paint(&painter);
+ painter.end();
+
+ if (m_actualRenderTarget == QSGPaintedItem::Image) {
+ m_texture->setImage(m_image);
+ m_texture->setDirtyRect(dirtyRect);
+ } else if (m_multisampledFbo) {
+ QGLFramebufferObject::blitFramebuffer(m_fbo, dirtyRect, m_multisampledFbo, dirtyRect);
+ }
+
+ m_dirtyContents = false;
+ m_dirtyRect = QRect();
+}
+
+void QSGPainterNode::update()
+{
+ if (m_dirtyRenderTarget)
+ updateRenderTarget();
+ if (m_dirtyGeometry)
+ updateGeometry();
+ if (m_dirtyTexture)
+ updateTexture();
+
+ m_dirtyGeometry = false;
+ m_dirtyRenderTarget = false;
+ m_dirtyTexture = false;
+}
+
+void QSGPainterNode::updateTexture()
+{
+ m_texture->setHasAlphaChannel(!m_opaquePainting);
+ m_material.setTexture(m_texture);
+ m_materialO.setTexture(m_texture);
+
+ markDirty(DirtyMaterial);
+}
+
+void QSGPainterNode::updateGeometry()
+{
+ QRectF source;
+ if (m_actualRenderTarget == QSGPaintedItem::Image)
+ source = QRectF(0, 1, 1, -1);
+ else
+ source = QRectF(0, 1, qreal(m_size.width()) / m_fboSize.width(), qreal(-m_size.height()) / m_fboSize.height());
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry,
+ QRectF(0, 0, m_size.width(), m_size.height()),
+ source);
+ markDirty(DirtyGeometry);
+}
+
+void QSGPainterNode::updateRenderTarget()
+{
+ if (!m_extensionsChecked) {
+ QList<QByteArray> extensions = QByteArray((const char *)glGetString(GL_EXTENSIONS)).split(' ');
+ m_multisamplingSupported = extensions.contains("GL_EXT_framebuffer_multisample")
+ && extensions.contains("GL_EXT_framebuffer_blit");
+ m_extensionsChecked = true;
+ }
+
+ m_dirtyContents = true;
+
+ QSGPaintedItem::RenderTarget oldTarget = m_actualRenderTarget;
+ if (m_preferredRenderTarget == QSGPaintedItem::Image) {
+ m_actualRenderTarget = QSGPaintedItem::Image;
+ } else {
+ if (!m_multisamplingSupported && m_smoothPainting)
+ m_actualRenderTarget = QSGPaintedItem::Image;
+ else
+ m_actualRenderTarget = QSGPaintedItem::FramebufferObject;
+ }
+ if (oldTarget != m_actualRenderTarget) {
+ m_image = QImage();
+ delete m_fbo;
+ delete m_multisampledFbo;
+ m_fbo = m_multisampledFbo = 0;
+ }
+
+ if (m_actualRenderTarget == QSGPaintedItem::FramebufferObject) {
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (m_fbo && !m_dirtyGeometry && (!ctx->format().sampleBuffers() || !m_multisamplingSupported))
+ return;
+
+ if (m_fboSize.isEmpty())
+ updateFBOSize();
+
+ delete m_fbo;
+ delete m_multisampledFbo;
+ m_fbo = m_multisampledFbo = 0;
+
+ if (m_smoothPainting && ctx->format().sampleBuffers() && m_multisamplingSupported) {
+ {
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setSamples(ctx->format().samples());
+ m_multisampledFbo = new QGLFramebufferObject(m_fboSize, format);
+ }
+ {
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::NoAttachment);
+ m_fbo = new QGLFramebufferObject(m_fboSize, format);
+ }
+ } else {
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ m_fbo = new QGLFramebufferObject(m_fboSize, format);
+ }
+ } else {
+ if (!m_image.isNull() && !m_dirtyGeometry)
+ return;
+
+ m_image = QImage(m_size, QImage::Format_ARGB32_Premultiplied);
+ m_image.fill(Qt::transparent);
+ }
+
+ QSGPainterTexture *texture = new QSGPainterTexture;
+ if (m_actualRenderTarget == QSGPaintedItem::Image) {
+ texture->setOwnsTexture(true);
+ texture->setTextureSize(m_size);
+ } else {
+ texture->setTextureId(m_fbo->texture());
+ texture->setOwnsTexture(false);
+ texture->setTextureSize(m_fboSize);
+ }
+
+ if (m_texture)
+ delete m_texture;
+
+ texture->setTextureSize(m_size);
+ m_texture = texture;
+ m_material.setFiltering(m_linear_filtering ? QSGTexture::Linear : QSGTexture::Nearest);
+ m_materialO.setFiltering(m_linear_filtering ? QSGTexture::Linear : QSGTexture::Nearest);
+}
+
+void QSGPainterNode::updateFBOSize()
+{
+ int fboWidth = qMax(QT_MINIMUM_FBO_SIZE, qt_next_power_of_two(m_size.width()));
+ int fboHeight = qMax(QT_MINIMUM_FBO_SIZE, qt_next_power_of_two(m_size.height()));
+ m_fboSize = QSize(fboWidth, fboHeight);
+}
+
+void QSGPainterNode::setPreferredRenderTarget(QSGPaintedItem::RenderTarget target)
+{
+ if (m_preferredRenderTarget == target)
+ return;
+
+ m_preferredRenderTarget = target;
+
+ m_dirtyRenderTarget = true;
+ m_dirtyGeometry = true;
+ m_dirtyTexture = true;
+}
+
+void QSGPainterNode::setSize(const QSize &size)
+{
+ if (size == m_size)
+ return;
+
+ m_size = size;
+ updateFBOSize();
+
+ if (m_fbo)
+ m_dirtyRenderTarget = m_fbo->size() != m_fboSize || m_dirtyRenderTarget;
+ else
+ m_dirtyRenderTarget = true;
+ m_dirtyGeometry = true;
+ m_dirtyTexture = true;
+}
+
+void QSGPainterNode::setDirty(bool d, const QRect &dirtyRect)
+{
+ m_dirtyContents = d;
+ m_dirtyRect = dirtyRect;
+
+ markDirty(DirtyMaterial);
+}
+
+void QSGPainterNode::setOpaquePainting(bool opaque)
+{
+ if (opaque == m_opaquePainting)
+ return;
+
+ m_opaquePainting = opaque;
+ m_dirtyTexture = true;
+}
+
+void QSGPainterNode::setLinearFiltering(bool linearFiltering)
+{
+ if (linearFiltering == m_linear_filtering)
+ return;
+
+ m_linear_filtering = linearFiltering;
+
+ m_material.setFiltering(linearFiltering ? QSGTexture::Linear : QSGTexture::Nearest);
+ m_materialO.setFiltering(linearFiltering ? QSGTexture::Linear : QSGTexture::Nearest);
+ markDirty(DirtyMaterial);
+}
+
+void QSGPainterNode::setSmoothPainting(bool s)
+{
+ if (s == m_smoothPainting)
+ return;
+
+ m_smoothPainting = s;
+ m_dirtyRenderTarget = true;
+}
+
+void QSGPainterNode::setFillColor(const QColor &c)
+{
+ if (c == m_fillColor)
+ return;
+
+ m_fillColor = c;
+ markDirty(DirtyMaterial);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgpainternode_p.h b/src/declarative/scenegraph/util/qsgpainternode_p.h
new file mode 100644
index 0000000000..ef1f3f1dde
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgpainternode_p.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPAINTERNODE_P_H
+#define QSGPAINTERNODE_P_H
+
+#include "qsgnode.h"
+#include "qsgtexturematerial.h"
+#include "qsgtexture_p.h"
+#include "qsgpainteditem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QGLFramebufferObject;
+
+class Q_DECLARATIVE_EXPORT QSGPainterTexture : public QSGPlainTexture
+{
+public:
+ QSGPainterTexture();
+
+ void setDirtyRect(const QRect &rect) { m_dirty_rect = rect; }
+
+ void bind();
+
+private:
+ QRect m_dirty_rect;
+};
+
+class Q_DECLARATIVE_EXPORT QSGPainterNode : public QSGGeometryNode
+{
+public:
+ QSGPainterNode(QSGPaintedItem *item);
+ virtual ~QSGPainterNode();
+
+ void setPreferredRenderTarget(QSGPaintedItem::RenderTarget target);
+
+ void setSize(const QSize &size);
+ QSize size() const { return m_size; }
+
+ void setDirty(bool d, const QRect &dirtyRect = QRect());
+
+ void setOpaquePainting(bool opaque);
+ bool opaquePainting() const { return m_opaquePainting; }
+
+ void setLinearFiltering(bool linearFiltering);
+ bool linearFiltering() const { return m_linear_filtering; }
+
+ void setSmoothPainting(bool s);
+ bool smoothPainting() const { return m_smoothPainting; }
+
+ void setFillColor(const QColor &c);
+ QColor fillColor() const { return m_fillColor; }
+
+ void update();
+
+ void preprocess();
+
+private:
+ void updateTexture();
+ void updateGeometry();
+ void updateRenderTarget();
+ void updateFBOSize();
+
+ QSGPaintedItem::RenderTarget m_preferredRenderTarget;
+ QSGPaintedItem::RenderTarget m_actualRenderTarget;
+
+ QSGPaintedItem *m_item;
+
+ QGLFramebufferObject *m_fbo;
+ QGLFramebufferObject *m_multisampledFbo;
+ QImage m_image;
+
+ QSGTextureMaterial m_material;
+ QSGTextureMaterialWithOpacity m_materialO;
+ QSGGeometry m_geometry;
+ QSGPainterTexture *m_texture;
+
+ QSize m_size;
+ QSize m_fboSize;
+ bool m_dirtyContents;
+ QRect m_dirtyRect;
+ bool m_opaquePainting;
+ bool m_linear_filtering;
+ bool m_smoothPainting;
+ bool m_extensionsChecked;
+ bool m_multisamplingSupported;
+ QColor m_fillColor;
+
+ bool m_dirtyGeometry;
+ bool m_dirtyRenderTarget;
+ bool m_dirtyTexture;
+};
+
+QT_END_HEADER
+
+QT_END_NAMESPACE
+
+#endif // QSGPAINTERNODE_P_H
diff --git a/src/declarative/scenegraph/util/qsgsimplerectnode.cpp b/src/declarative/scenegraph/util/qsgsimplerectnode.cpp
new file mode 100644
index 0000000000..604222dad5
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimplerectnode.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsimplerectnode.h"
+#include "qsgflatcolormaterial.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGSimpleRectNode
+
+ \brief The QSGSimpleRectNode class is a convenience class for drawing
+ solid filled rectangles using scenegraph.
+
+ */
+
+
+
+/*!
+ Constructs a QSGSimpleRectNode instance which is spanning \a rect with
+ the color \a color.
+ */
+QSGSimpleRectNode::QSGSimpleRectNode(const QRectF &rect, const QColor &color)
+ : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4)
+{
+ QSGGeometry::updateRectGeometry(&m_geometry, rect);
+ m_material.setColor(color);
+ setMaterial(&m_material);
+ setGeometry(&m_geometry);
+}
+
+
+
+/*!
+ Constructs a QSGSimpleRectNode instance with an empty rectangle and
+ white color.
+ */
+QSGSimpleRectNode::QSGSimpleRectNode()
+ : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4)
+{
+ QSGGeometry::updateRectGeometry(&m_geometry, QRectF());
+ setMaterial(&m_material);
+ setGeometry(&m_geometry);
+}
+
+
+
+/*!
+ Sets the rectangle of this rect node to \a rect.
+ */
+void QSGSimpleRectNode::setRect(const QRectF &rect)
+{
+ QSGGeometry::updateRectGeometry(&m_geometry, rect);
+ markDirty(QSGNode::DirtyGeometry);
+}
+
+
+
+/*!
+ Returns the rectangle that this rect node covers.
+ */
+QRectF QSGSimpleRectNode::rect() const
+{
+ const QSGGeometry::Point2D *pts = m_geometry.vertexDataAsPoint2D();
+ return QRectF(pts[0].x,
+ pts[0].y,
+ pts[3].x - pts[0].x,
+ pts[3].y - pts[0].y);
+}
+
+
+/*!
+ Sets the color of this rectangle to \a color. The default
+ color will be white.
+ */
+void QSGSimpleRectNode::setColor(const QColor &color)
+{
+ if (color != m_material.color()) {
+ m_material.setColor(color);
+ markDirty(QSGNode::DirtyMaterial);
+ }
+}
+
+
+
+/*!
+ Returns the color of this rectangle.
+ */
+QColor QSGSimpleRectNode::color() const
+{
+ return m_material.color();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgsimplerectnode.h b/src/declarative/scenegraph/util/qsgsimplerectnode.h
new file mode 100644
index 0000000000..ac001ab4eb
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimplerectnode.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SOLIDRECTNODE_H
+#define SOLIDRECTNODE_H
+
+#include "qsgnode.h"
+#include "qsgflatcolormaterial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QSGSimpleRectNode : public QSGGeometryNode
+{
+public:
+ QSGSimpleRectNode(const QRectF &rect, const QColor &color);
+ QSGSimpleRectNode();
+
+ void setRect(const QRectF &rect);
+ inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); }
+ QRectF rect() const;
+
+ void setColor(const QColor &color);
+ QColor color() const;
+
+private:
+ QSGFlatColorMaterial m_material;
+ QSGGeometry m_geometry;
+ void *reserved;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SOLIDRECTNODE_H
diff --git a/src/declarative/scenegraph/util/qsgsimpletexturenode.cpp b/src/declarative/scenegraph/util/qsgsimpletexturenode.cpp
new file mode 100644
index 0000000000..4e4567444a
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimpletexturenode.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qsgsimpletexturenode.h"
+
+QT_BEGIN_NAMESPACE
+
+static void qsgsimpletexturenode_update(QSGGeometry *g,
+ QSGTexture *texture,
+ const QRectF &rect)
+{
+ if (!texture)
+ return;
+
+ QSize ts = texture->textureSize();
+ QRectF sourceRect(0, ts.height(), ts.width(), -ts.height());
+ QSGGeometry::updateTexturedRectGeometry(g, rect, texture->convertToNormalizedSourceRect(sourceRect));
+}
+
+/*!
+ \class QSGSimpleTextureNode
+ \brief The QSGSimpleTextureNode provided for convenience to easily draw
+ textured content using the QML scene graph.
+
+ \warning The simple texture node class must have texture before being
+ added to the scene graph to be rendered.
+*/
+
+/*!
+ Constructs a new simple texture node
+ */
+QSGSimpleTextureNode::QSGSimpleTextureNode()
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+{
+ setGeometry(&m_geometry);
+ setMaterial(&m_opaque_material);
+ setOpaqueMaterial(&m_material);
+}
+
+/*!
+ Sets the filtering to be used for this texture node to \a filtering.
+
+ For smooth scaling, use QSGTexture::Linear; for normal scaling, use
+ QSGTexture::Nearest.
+ */
+void QSGSimpleTextureNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.filtering() == filtering)
+ return;
+
+ m_material.setFiltering(filtering);
+ m_opaque_material.setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+
+/*!
+ Returns the filtering currently set on this texture node
+ */
+QSGTexture::Filtering QSGSimpleTextureNode::filtering() const
+{
+ return m_material.filtering();
+}
+
+
+/*!
+ Sets the target rect of this texture node to \a r
+ */
+void QSGSimpleTextureNode::setRect(const QRectF &r)
+{
+ if (m_rect == r)
+ return;
+ m_rect = r;
+ qsgsimpletexturenode_update(&m_geometry, texture(), m_rect);
+ markDirty(DirtyGeometry);
+}
+
+
+/*!
+ Returns the target rect of this texture node.
+ */
+QRectF QSGSimpleTextureNode::rect() const
+{
+ return m_rect;
+}
+
+/*!
+ Sets the texture of this texture node to \a texture.
+
+ \warning A texture node must have a texture before being added
+ to the scenegraph to be rendered.
+ */
+void QSGSimpleTextureNode::setTexture(QSGTexture *texture)
+{
+ if (m_material.texture() == texture)
+ return;
+ m_material.setTexture(texture);
+ m_opaque_material.setTexture(texture);
+ qsgsimpletexturenode_update(&m_geometry, texture, m_rect);
+ markDirty(DirtyMaterial);
+}
+
+
+
+/*!
+ Returns the texture for this texture node
+ */
+QSGTexture *QSGSimpleTextureNode::texture() const
+{
+ return m_material.texture();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgsimpletexturenode.h b/src/declarative/scenegraph/util/qsgsimpletexturenode.h
new file mode 100644
index 0000000000..b4d8b71962
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimpletexturenode.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSIMPLETEXTURENODE_H
+#define QSGSIMPLETEXTURENODE_H
+
+#include "qsgnode.h"
+#include "qsggeometry.h"
+#include "qsgtexturematerial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QSGSimpleTextureNode : public QSGGeometryNode
+{
+public:
+ QSGSimpleTextureNode();
+
+ void setRect(const QRectF &rect);
+ inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); }
+ QRectF rect() const;
+
+ void setTexture(QSGTexture *texture);
+ QSGTexture *texture() const;
+
+ void setFiltering(QSGTexture::Filtering filtering);
+ QSGTexture::Filtering filtering() const;
+
+private:
+ QSGGeometry m_geometry;
+ QSGTextureMaterial m_opaque_material;
+ QSGTextureMaterialWithOpacity m_material;
+
+ QRectF m_rect;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGSIMPLETEXTURENODE_H
diff --git a/src/declarative/scenegraph/util/qsgtexture.cpp b/src/declarative/scenegraph/util/qsgtexture.cpp
new file mode 100644
index 0000000000..6112e777e4
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexture.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <private/qsgtexture_p.h>
+#include <qglfunctions.h>
+#include <private/qsgcontext_p.h>
+#include <qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGTexturePrivate::QSGTexturePrivate()
+ : wrapChanged(false)
+ , filteringChanged(false)
+ , horizontalWrap(QSGTexture::ClampToEdge)
+ , verticalWrap(QSGTexture::ClampToEdge)
+ , mipmapMode(QSGTexture::None)
+ , filterMode(QSGTexture::Nearest)
+{
+}
+
+#ifndef QT_NO_DEBUG
+static int qt_texture_count = 0;
+
+static void qt_print_texture_count()
+{
+ qDebug("Number of leaked textures: %i", qt_texture_count);
+ qt_texture_count = -1;
+}
+#endif
+
+
+
+QSGTexture::QSGTexture()
+ : QObject(*(new QSGTexturePrivate))
+{
+#ifndef QT_NO_DEBUG
+ ++qt_texture_count;
+ static bool atexit_registered = false;
+ if (!atexit_registered) {
+ atexit(qt_print_texture_count);
+ atexit_registered = true;
+ }
+#endif
+}
+
+QSGTexture::~QSGTexture()
+{
+#ifndef QT_NO_DEBUG
+ --qt_texture_count;
+ if (qt_texture_count < 0)
+ qDebug("Material destroyed after qt_print_texture_count() was called.");
+#endif
+}
+
+
+/*!
+ \fn void QSGTexture::setImage(const QImage &image)
+
+ This function may be calld from arbitrary an arbitrary thread and may not
+ use GL calls.
+ */
+
+
+/*!
+ \fn void QSGTexture::bind()
+
+ Call this function to bind this texture to the current texture
+ target.
+
+ Binding a texture may also include uploading the texture data from
+ a previously set QImage.
+ */
+
+void QSGTexture::removeFromAtlas()
+{
+ // default textures are not in atlasses, so do nothing...
+}
+
+/*!
+ Returns weither this texture is part of an atlas or not.
+
+ The default implementation returns false.
+ */
+bool QSGTexture::isAtlasTexture() const
+{
+ return false;
+}
+
+
+/*!
+ Returns the rectangle inside textureSize() that this texture
+ represents in normalized coordinates.
+
+ The default implementation returns a rect at position (0, 0) with
+ width and height of 1.
+ */
+QRectF QSGTexture::textureSubRect() const
+{
+ return QRectF(0, 0, 1, 1);
+}
+
+/*!
+ \fn bool QSGTexture::hasMipmaps() const
+
+ Returns true if the texture data contains mipmap levels.
+ */
+
+
+/*!
+ Sets the mipmap sampling mode to be used for the upcoming bind() call to \a filter.
+
+ Setting the mipmap filtering has no effect it the texture does not have mipmaps.
+
+ \sa hasMipmaps()
+ */
+void QSGTexture::setMipmapFiltering(Filtering filter)
+{
+ Q_D(QSGTexture);
+ if (d->mipmapMode != (uint) filter) {
+ d->mipmapMode = filter;
+ d->filteringChanged = true;
+ }
+}
+
+/*!
+ Returns whether mipmapping should be used when sampling from this texture.
+ */
+QSGTexture::Filtering QSGTexture::mipmapFiltering() const
+{
+ return (QSGTexture::Filtering) d_func()->mipmapMode;
+}
+
+
+/*!
+ Sets the sampling mode to be used for the upcoming bind() call to \a filter.
+ */
+void QSGTexture::setFiltering(QSGTexture::Filtering filter)
+{
+ Q_D(QSGTexture);
+ if (d->filterMode != (uint) filter) {
+ d->filterMode = filter;
+ d->filteringChanged = true;
+ }
+}
+
+QSGTexture::Filtering QSGTexture::filtering() const
+{
+ return (QSGTexture::Filtering) d_func()->filterMode;
+}
+
+
+
+/*!
+ Sets the horizontal wrap mode to be used for the upcoming bind() call to \a hwrap
+ */
+
+void QSGTexture::setHorizontalWrapMode(WrapMode hwrap)
+{
+ Q_D(QSGTexture);
+ if ((uint) hwrap != d->horizontalWrap) {
+ d->horizontalWrap = hwrap;
+ d->wrapChanged = true;
+ }
+}
+
+QSGTexture::WrapMode QSGTexture::horizontalWrapMode() const
+{
+ return (QSGTexture::WrapMode) d_func()->horizontalWrap;
+}
+
+
+
+void QSGTexture::setVerticalWrapMode(WrapMode vwrap)
+{
+ Q_D(QSGTexture);
+ if ((uint) vwrap != d->verticalWrap) {
+ d->verticalWrap = vwrap;
+ d->wrapChanged = true;
+ }
+}
+
+QSGTexture::WrapMode QSGTexture::verticalWrapMode() const
+{
+ return (QSGTexture::WrapMode) d_func()->verticalWrap;
+}
+
+
+/*!
+ Update the texture state to match the filtering, mipmap and wrap options
+ currently set.
+
+ If \a force is true, all properties will be updated regardless of weither
+ they have changed or not.
+ */
+void QSGTexture::updateBindOptions(bool force)
+{
+ Q_D(QSGTexture);
+ if (force || d->filteringChanged) {
+ bool linear = d->filterMode == Linear;
+ GLint minFilter = linear ? GL_LINEAR : GL_NEAREST;
+ GLint magFilter = linear ? GL_LINEAR : GL_NEAREST;
+
+ if (hasMipmaps()) {
+ if (d->mipmapMode == Nearest)
+ minFilter = linear ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST;
+ else if (d->mipmapMode == Linear)
+ minFilter = linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR;
+ }
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
+ d->filteringChanged = false;
+ }
+
+ if (force || d->wrapChanged) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, d->horizontalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, d->verticalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
+ d->wrapChanged = false;
+ }
+}
+
+QSGPlainTexture::QSGPlainTexture()
+ : QSGTexture()
+ , m_texture_id(0)
+ , m_has_alpha(false)
+ , m_has_mipmaps(false)
+ , m_dirty_bind_options(false)
+ , m_owns_texture(true)
+ , m_mipmaps_generated(false)
+{
+}
+
+
+QSGPlainTexture::~QSGPlainTexture()
+{
+ if (m_texture_id && m_owns_texture)
+ glDeleteTextures(1, &m_texture_id);
+}
+
+#ifdef QT_OPENGL_ES
+static void swizzleBGRAToRGBA(QImage *image)
+{
+ const int width = image->width();
+ const int height = image->height();
+ for (int i = 0; i < height; ++i) {
+ uint *p = (uint *) image->scanLine(i);
+ for (int x = 0; x < width; ++x)
+ p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
+ }
+}
+#endif
+
+void QSGPlainTexture::setImage(const QImage &image)
+{
+ m_image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+#ifdef QT_OPENGL_ES
+ swizzleBGRAToRGBA(&m_image);
+#endif
+
+ m_texture_size = image.size();
+ m_has_alpha = image.hasAlphaChannel();
+ m_dirty_texture = true;
+ m_dirty_bind_options = true;
+ }
+
+void QSGPlainTexture::setTextureId(int id)
+{
+ if (m_texture_id && m_owns_texture)
+ glDeleteTextures(1, &m_texture_id);
+
+ m_texture_id = id;
+ m_dirty_texture = false;
+ m_dirty_bind_options = true;
+ m_image = QImage();
+ m_mipmaps_generated = false;
+}
+
+void QSGPlainTexture::setHasMipmaps(bool mm)
+{
+ m_has_mipmaps = mm;
+ m_mipmaps_generated = false;
+}
+
+
+void QSGPlainTexture::bind()
+{
+ if (!m_dirty_texture) {
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+ if (m_has_mipmaps && !m_mipmaps_generated) {
+ const QGLContext *ctx = QGLContext::currentContext();
+ ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ m_mipmaps_generated = true;
+ }
+ updateBindOptions(m_dirty_bind_options);
+ m_dirty_bind_options = false;
+ return;
+ }
+
+ m_dirty_texture = false;
+
+ if (m_texture_id && m_owns_texture)
+ glDeleteTextures(1, &m_texture_id);
+
+ if (m_image.isNull()) {
+ m_texture_id = 0;
+ m_texture_size = QSize();
+ m_has_mipmaps = false;
+ m_has_alpha = false;
+ return;
+ }
+
+ glGenTextures(1, &m_texture_id);
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+
+ // ### TODO: check for out-of-memory situations...
+ int w = m_image.width();
+ int h = m_image.height();
+
+#ifdef QT_OPENGL_ES
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ for (int i = 0; i < m_image.height(); ++i)
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, w, 1, GL_RGBA, GL_UNSIGNED_BYTE, m_image.constScanLine(h - 1 - i));
+#else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
+ for (int i = 0; i < m_image.height(); ++i)
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, w, 1, GL_BGRA, GL_UNSIGNED_BYTE, m_image.constScanLine(h - 1 - i));
+#endif
+
+ if (m_has_mipmaps) {
+ const QGLContext *ctx = QGLContext::currentContext();
+ ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ m_mipmaps_generated = true;
+ }
+
+ m_texture_size = QSize(w, h);
+
+ updateBindOptions(m_dirty_bind_options);
+ m_dirty_bind_options = false;
+}
+
+
+/*!
+ \class QSGDynamicTexture
+ \brief The QSGDynamicTexture class serves as a baseclass for dynamically changing textures,
+ such as content that is rendered to FBO's.
+
+ To update the content of the texture, call updateTexture() explicitly. Simply calling bind()
+ will not update the texture.
+ */
+
+
+/*!
+ \fn bool QSGDynamicTexture::updateTexture()
+
+ Call this function to explicitely update the dynamic texture. Calling bind() will bind
+ the content that was previously updated.
+
+ The function returns true if the texture was changed as a resul of the update; otherwise
+ returns false.
+ */
+
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgtexture.h b/src/declarative/scenegraph/util/qsgtexture.h
new file mode 100644
index 0000000000..807dbecae5
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexture.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTURE_H
+#define QSGTEXTURE_H
+
+#include <QObject>
+#include <QImage>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTexturePrivate;
+class Q_DECLARATIVE_EXPORT QSGTexture : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGTexture)
+
+public:
+ QSGTexture();
+ ~QSGTexture();
+
+ enum WrapMode {
+ Repeat,
+ ClampToEdge
+ };
+
+ enum Filtering {
+ None,
+ Nearest,
+ Linear
+ };
+
+ virtual int textureId() const = 0;
+ virtual QSize textureSize() const = 0;
+ virtual bool hasAlphaChannel() const = 0;
+ virtual bool hasMipmaps() const = 0;
+
+ virtual QRectF textureSubRect() const;
+
+ virtual bool isAtlasTexture() const;
+ virtual void removeFromAtlas();
+
+ virtual void bind() = 0;
+ void updateBindOptions(bool force = false);
+
+ void setMipmapFiltering(Filtering filter);
+ QSGTexture::Filtering mipmapFiltering() const;
+
+ void setFiltering(Filtering filter);
+ QSGTexture::Filtering filtering() const;
+
+ void setHorizontalWrapMode(WrapMode hwrap);
+ QSGTexture::WrapMode horizontalWrapMode() const;
+
+ void setVerticalWrapMode(WrapMode vwrap);
+ QSGTexture::WrapMode verticalWrapMode() const;
+
+ inline QRectF convertToNormalizedSourceRect(const QRectF &rect) const;
+
+protected:
+ QSGTexture(QSGTexturePrivate &dd);
+};
+
+QRectF QSGTexture::convertToNormalizedSourceRect(const QRectF &rect) const
+{
+ QSize s = textureSize();
+ QRectF r = textureSubRect();
+
+ qreal sx = r.width() / s.width();
+ qreal sy = r.height() / s.height();
+
+ return QRectF(r.x() + rect.x() * sx,
+ r.y() + rect.y() * sy,
+ rect.width() * sx,
+ rect.height() * sy);
+}
+
+
+class QSGDynamicTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ virtual bool updateTexture() = 0;
+
+Q_SIGNALS:
+ void textureChanged();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/util/qsgtexture_p.h b/src/declarative/scenegraph/util/qsgtexture_p.h
new file mode 100644
index 0000000000..8ea0930235
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexture_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTURE_P_H
+#define QSGTEXTURE_P_H
+
+#include <private/qobject_p.h>
+
+#include <QtOpenGL/qgl.h>
+
+#include "qsgtexture.h"
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGTexturePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGTexture);
+public:
+ QSGTexturePrivate();
+
+ uint wrapChanged : 1;
+ uint filteringChanged : 1;
+
+ uint horizontalWrap : 1;
+ uint verticalWrap : 1;
+ uint mipmapMode : 2;
+ uint filterMode : 2;
+};
+
+class Q_DECLARATIVE_EXPORT QSGPlainTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ QSGPlainTexture();
+ virtual ~QSGPlainTexture();
+
+ void setOwnsTexture(bool owns) { m_owns_texture = owns; }
+ bool ownsTexture() const { return m_owns_texture; }
+
+ void setTextureId(int id);
+ int textureId() const { return m_texture_id; }
+
+ void setTextureSize(const QSize &size) { m_texture_size = size; }
+ QSize textureSize() const { return m_texture_size; }
+
+ void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; }
+ bool hasAlphaChannel() const { return m_has_alpha; }
+
+ void setHasMipmaps(bool mm);
+ bool hasMipmaps() const { return m_has_mipmaps; }
+
+ void setImage(const QImage &image);
+
+ virtual void bind();
+
+protected:
+ QImage m_image;
+
+ GLuint m_texture_id;
+ QSize m_texture_size;
+
+ uint m_has_alpha : 1;
+ uint m_has_mipmaps : 1;
+ uint m_dirty_texture : 1;
+ uint m_dirty_bind_options : 1;
+ uint m_owns_texture : 1;
+ uint m_mipmaps_generated : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTEXTURE_P_H
diff --git a/src/declarative/scenegraph/util/qsgtexturematerial.cpp b/src/declarative/scenegraph/util/qsgtexturematerial.cpp
new file mode 100644
index 0000000000..717bf82090
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexturematerial.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtexturematerial_p.h"
+
+#include <qglshaderprogram.h>
+
+QT_BEGIN_NAMESPACE
+
+const char qt_scenegraph_texture_material_vertex_code[] =
+ "uniform highp mat4 qt_Matrix; \n"
+ "attribute highp vec4 qt_VertexPosition; \n"
+ "attribute highp vec2 qt_VertexTexCoord; \n"
+ "varying highp vec2 qt_TexCoord; \n"
+ "void main() { \n"
+ " qt_TexCoord = qt_VertexTexCoord; \n"
+ " gl_Position = qt_Matrix * qt_VertexPosition; \n"
+ "}";
+
+const char qt_scenegraph_texture_material_fragment[] =
+ "varying highp vec2 qt_TexCoord; \n"
+ "uniform sampler2D qt_Texture; \n"
+ "void main() { \n"
+ " gl_FragColor = texture2D(qt_Texture, qt_TexCoord);\n"
+ "}";
+
+
+const char *QSGTextureMaterialShader::vertexShader() const
+{
+ return qt_scenegraph_texture_material_vertex_code;
+}
+
+const char *QSGTextureMaterialShader::fragmentShader() const
+{
+ return qt_scenegraph_texture_material_fragment;
+}
+
+QSGMaterialType QSGTextureMaterialShader::type;
+
+char const *const *QSGTextureMaterialShader::attributeNames() const
+{
+ static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 };
+ return attr;
+}
+
+void QSGTextureMaterialShader::initialize()
+{
+ m_matrix_id = m_program.uniformLocation("qt_Matrix");
+}
+
+void QSGTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGTextureMaterial *tx = static_cast<QSGTextureMaterial *>(newEffect);
+ QSGTextureMaterial *oldTx = static_cast<QSGTextureMaterial *>(oldEffect);
+
+ QSGTexture *t = tx->texture();
+
+ t->setFiltering(tx->filtering());
+ t->setHorizontalWrapMode(tx->horizontalWrapMode());
+ t->setVerticalWrapMode(tx->verticalWrapMode());
+ t->setMipmapFiltering(tx->mipmapFiltering());
+
+ if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId())
+ t->bind();
+ else
+ t->updateBindOptions();
+
+ if (state.isMatrixDirty())
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+}
+
+
+QSGTextureMaterial::QSGTextureMaterial()
+ : m_texture(0)
+ , m_filtering(QSGTexture::Nearest)
+ , m_mipmap_filtering(QSGTexture::Nearest)
+ , m_horizontal_wrap(QSGTexture::ClampToEdge)
+ , m_vertical_wrap(QSGTexture::ClampToEdge)
+{
+}
+
+
+
+QSGMaterialType *QSGTextureMaterial::type() const
+{
+ return &QSGTextureMaterialShader::type;
+}
+
+QSGMaterialShader *QSGTextureMaterial::createShader() const
+{
+ return new QSGTextureMaterialShader;
+}
+
+
+void QSGTextureMaterial::setTexture(QSGTexture *texture)
+{
+ m_texture = texture;
+ setFlag(Blending, m_texture ? m_texture->hasAlphaChannel() : false);
+}
+
+
+int QSGTextureMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGTextureMaterial *other = static_cast<const QSGTextureMaterial *>(o);
+ if (int diff = m_texture->textureId() - other->texture()->textureId())
+ return diff;
+ return int(m_filtering) - int(other->m_filtering);
+}
+
+// QSGTextureMaterialWithOpacity
+
+static const char qt_scenegraph_texture_material_opacity_fragment[] =
+ "varying highp vec2 qt_TexCoord; \n"
+ "uniform sampler2D qt_Texture; \n"
+ "uniform lowp float opacity; \n"
+ "void main() { \n"
+ " gl_FragColor = texture2D(qt_Texture, qt_TexCoord) * opacity; \n"
+ "}";
+
+class TextureMaterialWithOpacityShader : public QSGTextureMaterialShader
+{
+public:
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual void initialize();
+
+ static QSGMaterialType type;
+
+protected:
+ virtual const char *fragmentShader() const { return qt_scenegraph_texture_material_opacity_fragment; }
+
+ int m_opacity_id;
+};
+QSGMaterialType TextureMaterialWithOpacityShader::type;
+
+QSGMaterialType *QSGTextureMaterialWithOpacity::type() const
+{
+ return &TextureMaterialWithOpacityShader::type;
+}
+
+QSGMaterialShader *QSGTextureMaterialWithOpacity::createShader() const
+{
+ return new TextureMaterialWithOpacityShader;
+}
+
+void TextureMaterialWithOpacityShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ if (state.isOpacityDirty())
+ m_program.setUniformValue(m_opacity_id, state.opacity());
+
+ QSGTextureMaterialShader::updateState(state, newEffect, oldEffect);
+}
+
+void TextureMaterialWithOpacityShader::initialize()
+{
+ QSGTextureMaterialShader::initialize();
+ m_opacity_id = m_program.uniformLocation("opacity");
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgtexturematerial.h b/src/declarative/scenegraph/util/qsgtexturematerial.h
new file mode 100644
index 0000000000..db8e5aa43e
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexturematerial.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTUREMATERIAL_H
+#define TEXTUREMATERIAL_H
+
+#include "qsgmaterial.h"
+#include <qsgtexture.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class Q_DECLARATIVE_EXPORT QSGTextureMaterial : public QSGMaterial
+{
+public:
+ QSGTextureMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setTexture(QSGTexture *texture);
+ QSGTexture *texture() const { return m_texture; }
+
+ void setMipmapFiltering(QSGTexture::Filtering filtering) { m_mipmap_filtering = filtering; }
+ QSGTexture::Filtering mipmapFiltering() const { return (QSGTexture::Filtering) m_mipmap_filtering; }
+
+ void setFiltering(QSGTexture::Filtering filtering) { m_filtering = filtering; }
+ QSGTexture::Filtering filtering() const { return (QSGTexture::Filtering) m_filtering; }
+
+ void setHorizontalWrapMode(QSGTexture::WrapMode mode) { m_horizontal_wrap = mode; }
+ QSGTexture::WrapMode horizontalWrapMode() const { return (QSGTexture::WrapMode) m_horizontal_wrap; }
+
+ void setVerticalWrapMode(QSGTexture::WrapMode mode) { m_vertical_wrap = mode; }
+ QSGTexture::WrapMode verticalWrapMode() const { return (QSGTexture::WrapMode) m_vertical_wrap; }
+
+protected:
+ QSGTexture *m_texture;
+
+ uint m_filtering: 2;
+ uint m_mipmap_filtering: 2;
+ uint m_vertical_wrap: 1;
+ uint m_horizontal_wrap : 1;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGTextureMaterialWithOpacity : public QSGTextureMaterial
+{
+public:
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // TEXTUREMATERIAL_H
diff --git a/src/declarative/scenegraph/util/qsgtexturematerial_p.h b/src/declarative/scenegraph/util/qsgtexturematerial_p.h
new file mode 100644
index 0000000000..6b811c6b2e
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexturematerial_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTUREMATERIAL_P_H
+#define TEXTUREMATERIAL_P_H
+
+#include "qsgtexturematerial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QSGTextureMaterialShader : public QSGMaterialShader
+{
+public:
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+ static QSGMaterialType type;
+
+protected:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ int m_matrix_id;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGTEXTUREMATERIAL_P_H
diff --git a/src/declarative/scenegraph/util/qsgtextureprovider.cpp b/src/declarative/scenegraph/util/qsgtextureprovider.cpp
new file mode 100644
index 0000000000..b41188772e
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtextureprovider.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtextureprovider_p.h"
+
+#ifndef GL_CLAMP_TO_EDGE
+#define GL_CLAMP_TO_EDGE 0x812F
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGTextureProvider
+ \brief The QSGTextureProvider class encapsulates texture based entities in QML.
+ */
+
+
+/*!
+ Convenience function for casting a QObject to a QSGTextureProvider
+ */
+QSGTextureProvider *QSGTextureProvider::from(QObject *object)
+{
+ return static_cast<QSGTextureProvider *>(object->qt_metacast("QSGTextureProvider"));
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgtextureprovider_p.h b/src/declarative/scenegraph/util/qsgtextureprovider_p.h
new file mode 100644
index 0000000000..1e0e9f6c68
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtextureprovider_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTUREPROVIDER_H
+#define QSGTEXTUREPROVIDER_H
+
+#include <qgl.h>
+
+#include "qsgtexture.h"
+#include "qobject.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTextureProvider
+{
+public:
+ virtual QSGTexture *texture() const = 0;
+ virtual const char *textureChangedSignal() { return 0; }
+
+ static QSGTextureProvider *from(QObject *object);
+};
+Q_DECLARE_INTERFACE(QSGTextureProvider, "QSGTextureProvider")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp b/src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp
new file mode 100644
index 0000000000..bbd57ea1c2
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgvertexcolormaterial_p.h"
+
+#include <qglshaderprogram.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGVertexColorMaterialShader : public QSGMaterialShader
+{
+public:
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+ static QSGMaterialType type;
+
+private:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ int m_matrix_id;
+ int m_opacity_id;
+};
+
+QSGMaterialType QSGVertexColorMaterialShader::type;
+
+void QSGVertexColorMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+{
+ if (!(newEffect->flags() & QSGMaterial::Blending) || state.isOpacityDirty())
+ m_program.setUniformValue(m_opacity_id, state.opacity());
+
+ if (state.isMatrixDirty())
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+}
+
+char const *const *QSGVertexColorMaterialShader::attributeNames() const
+{
+ static const char *const attr[] = { "vertexCoord", "vertexColor", 0 };
+ return attr;
+}
+
+void QSGVertexColorMaterialShader::initialize()
+{
+ m_matrix_id = m_program.uniformLocation("matrix");
+ m_opacity_id = m_program.uniformLocation("opacity");
+}
+
+const char *QSGVertexColorMaterialShader::vertexShader() const {
+ return
+ "attribute highp vec4 vertexCoord; \n"
+ "attribute highp vec4 vertexColor; \n"
+ "uniform highp mat4 matrix; \n"
+ "uniform highp float opacity; \n"
+ "varying lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_Position = matrix * vertexCoord; \n"
+ " color = vertexColor * opacity; \n"
+ "}";
+}
+
+const char *QSGVertexColorMaterialShader::fragmentShader() const {
+ return
+ "varying lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color; \n"
+ "}";
+}
+
+
+QSGVertexColorMaterial::QSGVertexColorMaterial(bool opaque) : m_opaque(opaque)
+{
+ setFlag(Blending, !opaque);
+}
+
+void QSGVertexColorMaterial::setOpaque(bool opaque)
+{
+ setFlag(Blending, !opaque);
+ m_opaque = opaque;
+}
+
+QSGMaterialType *QSGVertexColorMaterial::type() const
+{
+ return &QSGVertexColorMaterialShader::type;
+}
+
+QSGMaterialShader *QSGVertexColorMaterial::createShader() const
+{
+ return new QSGVertexColorMaterialShader;
+}
+
+bool QSGVertexColorMaterial::is(const QSGMaterial *effect)
+{
+ return effect->type() == &QSGVertexColorMaterialShader::type;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h b/src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h
new file mode 100644
index 0000000000..9f5e0ed1db
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VERTEXCOLORMATERIAL_H
+#define VERTEXCOLORMATERIAL_H
+
+#include <qsgmaterial.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGVertexColorMaterial : public QSGMaterial
+{
+public:
+ QSGVertexColorMaterial(bool opaque = false);
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+
+ void setOpaque(bool opaque);
+ bool opaque() const { return m_opaque; }
+
+ static bool is(const QSGMaterial *effect);
+
+private:
+ bool m_opaque;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // VERTEXCOLORMATERIAL_H
diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp
index a29854fa84..dcce7db813 100644
--- a/src/declarative/util/qdeclarativepixmapcache.cpp
+++ b/src/declarative/util/qdeclarativepixmapcache.cpp
@@ -47,6 +47,10 @@
#include <private/qdeclarativeglobal_p.h>
#include <private/qdeclarativeengine_p.h>
+#include <qsgtexture.h>
+#include <private/qsgtexture_p.h>
+#include <private/qsgcontext_p.h>
+
#include <QCoreApplication>
#include <QImageReader>
#include <QHash>
@@ -75,7 +79,7 @@ QT_BEGIN_NAMESPACE
#if defined(Q_WS_QWS) || defined(Q_WS_WINCE)
static int cache_limit = 2048 * 1024; // 2048 KB cache limit for embedded
#else
-static int cache_limit = 10240 * 1024; // 10 MB cache limit for desktop
+static int cache_limit = 128 * 1024; // 10 MB cache limit for desktop
#endif
class QDeclarativePixmapReader;
@@ -98,14 +102,18 @@ public:
class Event : public QEvent {
public:
- Event(ReadError, const QString &, const QSize &, const QImage &);
+ Event(ReadError, const QString &, const QSize &, const QImage &image);
+ Event(ReadError, const QString &, const QSize &, QSGTexture *t, QSGContext *context);
ReadError error;
QString errorString;
QSize implicitSize;
QImage image;
+ QSGTexture *texture;
+ QSGContext *context;
};
void postReply(ReadError, const QString &, const QSize &, const QImage &);
+ void postReply(ReadError, const QString &, const QSize &, QSGTexture *t, QSGContext *context);
Q_SIGNALS:
@@ -184,32 +192,46 @@ class QDeclarativePixmapData
public:
QDeclarativePixmapData(const QUrl &u, const QSize &s, const QString &e)
: refCount(1), inCache(false), pixmapStatus(QDeclarativePixmap::Error),
- url(u), errorString(e), requestSize(s), reply(0), prevUnreferenced(0),
+ url(u), errorString(e), requestSize(s), texture(0), context(0), reply(0), prevUnreferenced(0),
prevUnreferencedPtr(0), nextUnreferenced(0)
{
}
QDeclarativePixmapData(const QUrl &u, const QSize &r)
: refCount(1), inCache(false), pixmapStatus(QDeclarativePixmap::Loading),
- url(u), requestSize(r), reply(0), prevUnreferenced(0), prevUnreferencedPtr(0),
+ url(u), requestSize(r), texture(0), context(0), reply(0), prevUnreferenced(0), prevUnreferencedPtr(0),
nextUnreferenced(0)
{
}
QDeclarativePixmapData(const QUrl &u, const QPixmap &p, const QSize &s, const QSize &r)
- : refCount(1), inCache(false), privatePixmap(false), pixmapStatus(QDeclarativePixmap::Ready),
- url(u), pixmap(p), implicitSize(s), requestSize(r), reply(0), prevUnreferenced(0),
+ : refCount(1), inCache(false), privatePixmap(false), pixmapStatus(QDeclarativePixmap::Ready),
+ url(u), pixmap(p), implicitSize(s), requestSize(r), texture(0), context(0), reply(0), prevUnreferenced(0),
+ prevUnreferencedPtr(0), nextUnreferenced(0)
+ {
+ }
+
+ QDeclarativePixmapData(const QUrl &u, QSGTexture *t, QSGContext *c, const QSize &s, const QSize &r)
+ : refCount(1), inCache(false), privatePixmap(false), pixmapStatus(QDeclarativePixmap::Ready),
+ url(u), implicitSize(s), requestSize(r), texture(t), context(c), reply(0), prevUnreferenced(0),
prevUnreferencedPtr(0), nextUnreferenced(0)
{
}
QDeclarativePixmapData(const QPixmap &p)
: refCount(1), inCache(false), privatePixmap(true), pixmapStatus(QDeclarativePixmap::Ready),
- pixmap(p), implicitSize(p.size()), requestSize(p.size()), reply(0), prevUnreferenced(0),
+ pixmap(p), implicitSize(p.size()), requestSize(p.size()), texture(0), context(0), reply(0), prevUnreferenced(0),
prevUnreferencedPtr(0), nextUnreferenced(0)
{
}
+ ~QDeclarativePixmapData()
+ {
+ if (texture && context) {
+ context->schdelueTextureForCleanup(texture);
+ }
+ }
+
int cost() const;
void addref();
void release();
@@ -228,6 +250,9 @@ public:
QSize implicitSize;
QSize requestSize;
+ QSGTexture *texture;
+ QSGContext *context;
+
QDeclarativePixmapReply *reply;
QDeclarativePixmapData *prevUnreferenced;
@@ -248,15 +273,28 @@ int QDeclarativePixmapReader::downloadProgress = -1;
int QDeclarativePixmapReader::threadNetworkRequestDone = -1;
-void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorString,
+void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorString,
const QSize &implicitSize, const QImage &image)
{
loading = false;
QCoreApplication::postEvent(this, new Event(error, errorString, implicitSize, image));
}
+void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorString,
+ const QSize &implicitSize, QSGTexture *texture,
+ QSGContext *context)
+{
+ loading = false;
+ QCoreApplication::postEvent(this, new Event(error, errorString, implicitSize, texture, context));
+}
+
QDeclarativePixmapReply::Event::Event(ReadError e, const QString &s, const QSize &iSize, const QImage &i)
-: QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), image(i)
+ : QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), image(i)
+{
+}
+
+QDeclarativePixmapReply::Event::Event(ReadError e, const QString &s, const QSize &iSize, QSGTexture *t, QSGContext *c)
+ : QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), texture(t), context(c)
{
}
@@ -355,6 +393,8 @@ void QDeclarativePixmapReader::networkRequestDone(QNetworkReply *reply)
}
QImage image;
+ QSGTexture *texture = 0;
+ QSGContext *ctx = QDeclarativeEnginePrivate::get(engine)->sgContext;
QDeclarativePixmapReply::ReadError error = QDeclarativePixmapReply::NoError;
QString errorString;
QSize readSize;
@@ -365,13 +405,26 @@ void QDeclarativePixmapReader::networkRequestDone(QNetworkReply *reply)
QByteArray all = reply->readAll();
QBuffer buff(&all);
buff.open(QIODevice::ReadOnly);
- if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize)) {
- error = QDeclarativePixmapReply::Decoding;
+ if (ctx && ctx->canDecodeImageToTexture())
+ texture = ctx->decodeImageToTexture(&buff, &readSize, job->requestSize);
+ if (!texture) {
+ if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize)) {
+ error = QDeclarativePixmapReply::Decoding;
+ } else if (ctx) {
+ texture = ctx->createTexture(image);
+ }
}
}
// send completion event to the QDeclarativePixmapReply
mutex.lock();
- if (!cancelled.contains(job)) job->postReply(error, errorString, readSize, image);
+ if (!cancelled.contains(job)) {
+ if (texture)
+ job->postReply(error, errorString, readSize, texture, ctx);
+ else
+ job->postReply(error, errorString, readSize, image);
+ } else {
+ delete texture;
+ }
mutex.unlock();
}
reply->deleteLater();
@@ -446,23 +499,46 @@ void QDeclarativePixmapReader::processJobs()
void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, const QUrl &url,
const QSize &requestSize)
{
+ QSGContext *sgContext = QDeclarativeEnginePrivate::get(engine)->sgContext;
+
// fetch
if (url.scheme() == QLatin1String("image")) {
// Use QmlImageProvider
QSize readSize;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
+ QDeclarativeImageProvider::ImageType imageType = ep->getImageProviderType(url);
+
+ if (imageType == QDeclarativeImageProvider::Image) {
+ QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
+ QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError;
+ QString errorStr;
+ if (image.isNull()) {
+ errorCode = QDeclarativePixmapReply::Loading;
+ errorStr = QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString());
+ }
+ mutex.lock();
+ if (!cancelled.contains(runningJob)) {
+ if (sgContext)
+ runningJob->postReply(errorCode, errorStr, readSize, sgContext->createTexture(image), sgContext);
+ else
+ runningJob->postReply(errorCode, errorStr, readSize, image);
+ }
+ mutex.unlock();
+ } else {
+ QSGTexture *t = ep->getTextureFromProvider(url, &readSize, requestSize);
+ QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError;
+ QString errorStr;
+ if (!t) {
+ errorCode = QDeclarativePixmapReply::Loading;
+ errorStr = QDeclarativePixmap::tr("Failed to get texture from provider: %1").arg(url.toString());
+ }
+ mutex.lock();
+ if (!cancelled.contains(runningJob))
+ runningJob->postReply(errorCode, errorStr, readSize, t, sgContext);
+ mutex.unlock();
- QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError;
- QString errorStr;
- if (image.isNull()) {
- errorCode = QDeclarativePixmapReply::Loading;
- errorStr = QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString());
}
- mutex.lock();
- if (!cancelled.contains(runningJob)) runningJob->postReply(errorCode, errorStr, readSize, image);
- mutex.unlock();
} else {
QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
if (!lf.isEmpty()) {
@@ -472,15 +548,30 @@ void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, c
QString errorStr;
QFile f(lf);
QSize readSize;
+ QSGTexture *texture = 0;
if (f.open(QIODevice::ReadOnly)) {
- if (!readImage(url, &f, &image, &errorStr, &readSize, requestSize))
- errorCode = QDeclarativePixmapReply::Loading;
+ if (sgContext && sgContext ->canDecodeImageToTexture())
+ texture = sgContext->decodeImageToTexture(&f, &readSize, requestSize);
+ if (!texture) {
+ if (!readImage(url, &f, &image, &errorStr, &readSize, requestSize)) {
+ errorCode = QDeclarativePixmapReply::Loading;
+ } else if (sgContext) {
+ texture = sgContext->createTexture(image);
+ }
+ }
} else {
errorStr = QDeclarativePixmap::tr("Cannot open: %1").arg(url.toString());
errorCode = QDeclarativePixmapReply::Loading;
}
mutex.lock();
- if (!cancelled.contains(runningJob)) runningJob->postReply(errorCode, errorStr, readSize, image);
+ if (!cancelled.contains(runningJob)) {
+ if (texture)
+ runningJob->postReply(errorCode, errorStr, readSize, texture, sgContext);
+ else
+ runningJob->postReply(errorCode, errorStr, readSize, image);
+ } else {
+ delete texture;
+ }
mutex.unlock();
} else {
// Network resource
@@ -704,7 +795,11 @@ bool QDeclarativePixmapReply::event(QEvent *event)
data->pixmapStatus = (de->error == NoError) ? QDeclarativePixmap::Ready : QDeclarativePixmap::Error;
if (data->pixmapStatus == QDeclarativePixmap::Ready) {
- data->pixmap = QPixmap::fromImage(de->image);
+ if (de->texture) {
+ data->texture = de->texture;
+ data->context = de->context;
+ } else
+ data->pixmap = QPixmap::fromImage(de->image);
data->implicitSize = de->implicitSize;
} else {
data->errorString = de->errorString;
@@ -774,17 +869,32 @@ void QDeclarativePixmapData::removeFromCache()
static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine, const QUrl &url, const QSize &requestSize, bool *ok)
{
+ QSGContext *sgContext = QDeclarativeEnginePrivate::get(engine)->sgContext;
+
if (url.scheme() == QLatin1String("image")) {
QSize readSize;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
QDeclarativeImageProvider::ImageType imageType = ep->getImageProviderType(url);
switch (imageType) {
+ case QDeclarativeImageProvider::Texture:
+ {
+ QSGTexture *texture = ep->getTextureFromProvider(url, &readSize, requestSize);
+ if (texture) {
+ *ok = true;
+ return new QDeclarativePixmapData(url, texture, sgContext, readSize, requestSize);
+ }
+ }
+
case QDeclarativeImageProvider::Image:
{
QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
if (!image.isNull()) {
*ok = true;
+ if (sgContext) {
+ QSGTexture *t = sgContext->createTexture(image);
+ return new QDeclarativePixmapData(url, t, sgContext,readSize, requestSize);
+ }
return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
}
}
@@ -793,6 +903,10 @@ static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine,
QPixmap pixmap = ep->getPixmapFromProvider(url, &readSize, requestSize);
if (!pixmap.isNull()) {
*ok = true;
+ if (sgContext) {
+ QSGTexture *t = sgContext->createTexture(pixmap.toImage());
+ return new QDeclarativePixmapData(url, t, sgContext,readSize, requestSize);
+ }
return new QDeclarativePixmapData(url, pixmap, readSize, requestSize);
}
}
@@ -812,11 +926,29 @@ static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine,
QString errorString;
if (f.open(QIODevice::ReadOnly)) {
+ QSGContext *ctx = QDeclarativeEnginePrivate::get(engine)->sgContext;
+ QSGTexture *texture = 0;
QImage image;
- if (readImage(url, &f, &image, &errorString, &readSize, requestSize)) {
+
+ if (ctx && ctx->canDecodeImageToTexture()) {
+ texture = ctx->decodeImageToTexture(&f, &readSize, requestSize);
*ok = true;
- return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
}
+
+ if (!texture) {
+ if (readImage(url, &f, &image, &errorString, &readSize, requestSize))
+ *ok = true;
+
+ if (ok && ctx) {
+ texture = ctx->createTexture(image);
+ }
+ }
+
+ if (texture)
+ return new QDeclarativePixmapData(url, texture, ctx, readSize, requestSize);
+ else
+ return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
+
} else {
errorString = QDeclarativePixmap::tr("Cannot open: %1").arg(url.toString());
}
@@ -916,6 +1048,11 @@ const QSize &QDeclarativePixmap::requestSize() const
return nullPixmap()->size;
}
+QSGTexture *QDeclarativePixmap::texture() const
+{
+ return d ? d->texture : 0;
+}
+
const QPixmap &QDeclarativePixmap::pixmap() const
{
if (d)
@@ -935,7 +1072,7 @@ void QDeclarativePixmap::setPixmap(const QPixmap &p)
int QDeclarativePixmap::width() const
{
if (d)
- return d->pixmap.width();
+ return d->texture ? d->texture->textureSize().width() : d->pixmap.width();
else
return 0;
}
@@ -943,7 +1080,7 @@ int QDeclarativePixmap::width() const
int QDeclarativePixmap::height() const
{
if (d)
- return d->pixmap.height();
+ return d->texture? d->texture->textureSize().height() : d->pixmap.height();
else
return 0;
}
@@ -951,7 +1088,7 @@ int QDeclarativePixmap::height() const
QRect QDeclarativePixmap::rect() const
{
if (d)
- return d->pixmap.rect();
+ return d->texture ? QRect(QPoint(), d->texture->textureSize()) : d->pixmap.rect();
else
return QRect();
}
diff --git a/src/declarative/util/qdeclarativepixmapcache_p.h b/src/declarative/util/qdeclarativepixmapcache_p.h
index 1cf76dda71..b917693e3e 100644
--- a/src/declarative/util/qdeclarativepixmapcache_p.h
+++ b/src/declarative/util/qdeclarativepixmapcache_p.h
@@ -55,6 +55,8 @@ QT_MODULE(Declarative)
class QDeclarativeEngine;
class QDeclarativePixmapData;
+class QSGTexture;
+
class Q_DECLARATIVE_EXPORT QDeclarativePixmap
{
Q_DECLARE_TR_FUNCTIONS(QDeclarativePixmap)
@@ -85,6 +87,8 @@ public:
const QPixmap &pixmap() const;
void setPixmap(const QPixmap &);
+ QSGTexture *texture() const;
+
QRect rect() const;
int width() const;
int height() const;
diff --git a/src/imports/etcprovider/etcprovider.pro b/src/imports/etcprovider/etcprovider.pro
new file mode 100644
index 0000000000..b48235eed8
--- /dev/null
+++ b/src/imports/etcprovider/etcprovider.pro
@@ -0,0 +1,19 @@
+TARGET = qmletcproviderplugin
+TARGETPATH = Qt/labs/etcprovider
+include(../qimportbase.pri)
+!contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL
+
+QT += declarative opengl
+
+SOURCES += qetcprovider.cpp plugin.cpp
+HEADERS += qetcprovider.h plugin.h
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/imports/$$TARGETPATH
+target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+qmldir.files += $$PWD/qmldir
+qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+INSTALLS += target qmldir
+
+OTHER_FILES +=
diff --git a/src/imports/etcprovider/plugin.cpp b/src/imports/etcprovider/plugin.cpp
new file mode 100644
index 0000000000..ac2d803842
--- /dev/null
+++ b/src/imports/etcprovider/plugin.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "plugin.h"
+#include "qetcprovider.h"
+
+#include <QDeclarativeEngine>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEtcDummyObject : public QObject
+{
+public:
+ QEtcDummyObject() {}
+};
+
+void EtcProviderPlugin::registerTypes(const char *uri)
+{
+ //### this is required or "import Qt.labs.etcprovider 1.0" will give errors
+ //### this plugin should eventually be replaced by a non-import type plugin
+ // (once it is available)
+ qmlRegisterType<QEtcDummyObject>(uri,1,0,"EtcObject");
+}
+
+void EtcProviderPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri)
+{
+ qDebug () << uri;
+ engine->addImageProvider(QLatin1String("etc"), new QEtcProvider());
+}
+
+QT_END_NAMESPACE
+
+Q_EXPORT_PLUGIN2(qmletcproviderplugin, QT_PREPEND_NAMESPACE(EtcProviderPlugin))
diff --git a/src/imports/particles/particles.cpp b/src/imports/etcprovider/plugin.h
index ca2b0609cb..b697f72679 100644
--- a/src/imports/particles/particles.cpp
+++ b/src/imports/etcprovider/plugin.h
@@ -1,10 +1,10 @@
/****************************************************************************
**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
-** This file is part of the plugins of the Qt Toolkit.
+** This file is part of the demonstration applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
@@ -39,31 +39,30 @@
**
****************************************************************************/
-#include <QtDeclarative/qdeclarativeextensionplugin.h>
+#ifndef ETCPROVIDERPLUGIN_H
+#define ETCPROVIDERPLUGIN_H
+
#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/QDeclarativeExtensionPlugin>
-#include "qdeclarativeparticles_p.h"
+QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-class QParticlesQmlModule : public QDeclarativeExtensionPlugin
+QT_MODULE(Declarative)
+
+class EtcProviderPlugin : public QDeclarativeExtensionPlugin
{
Q_OBJECT
+
public:
- virtual void registerTypes(const char *uri)
- {
- Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.particles"));
- qmlRegisterType<QDeclarativeParticleMotion>(uri,1,0,"ParticleMotion");
- qmlRegisterType<QDeclarativeParticleMotionGravity>(uri,1,0,"ParticleMotionGravity");
- qmlRegisterType<QDeclarativeParticleMotionLinear>(uri,1,0,"ParticleMotionLinear");
- qmlRegisterType<QDeclarativeParticleMotionWander>(uri,1,0,"ParticleMotionWander");
- qmlRegisterType<QDeclarativeParticles>(uri,1,0,"Particles");
- }
+ void registerTypes(const char *uri);
+ void initializeEngine(QDeclarativeEngine *engine, const char *uri);
};
QT_END_NAMESPACE
-#include "particles.moc"
+QT_END_HEADER
-Q_EXPORT_PLUGIN2(qmlparticlesplugin, QT_PREPEND_NAMESPACE(QParticlesQmlModule));
+#endif // ETCPROVIDERPLUGIN_H
diff --git a/src/imports/etcprovider/qetcprovider.cpp b/src/imports/etcprovider/qetcprovider.cpp
new file mode 100644
index 0000000000..24513edc43
--- /dev/null
+++ b/src/imports/etcprovider/qetcprovider.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qetcprovider.h"
+
+#include <QtDebug>
+#include <QFile>
+
+#include <qglfunctions.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef struct {
+ char aName[6];
+ unsigned short iBlank;
+ /* NB: Beware endianess issues here. */
+ unsigned char iPaddedWidthMSB;
+ unsigned char iPaddedWidthLSB;
+ unsigned char iPaddedHeightMSB;
+ unsigned char iPaddedHeightLSB;
+ unsigned char iWidthMSB;
+ unsigned char iWidthLSB;
+ unsigned char iHeightMSB;
+ unsigned char iHeightLSB;
+} ETCHeader;
+
+
+unsigned short getWidth(ETCHeader *pHeader)
+{
+ return (pHeader->iWidthMSB << 8) | pHeader->iWidthLSB;
+}
+
+unsigned short getHeight(ETCHeader *pHeader)
+{
+ return (pHeader->iHeightMSB << 8) | pHeader->iHeightLSB;
+}
+
+unsigned short getPaddedWidth(ETCHeader *pHeader)
+{
+ return (pHeader->iPaddedWidthMSB << 8) | pHeader->iPaddedWidthLSB;
+}
+
+unsigned short getPaddedHeight(ETCHeader *pHeader)
+{
+ return (pHeader->iPaddedHeightMSB << 8) | pHeader->iPaddedHeightLSB;
+}
+
+enum {GL_ETC1_RGB8_OES=0x8d64};
+
+EtcTexture::EtcTexture()
+ : m_texture_id(0)
+{
+
+}
+
+EtcTexture::~EtcTexture()
+{
+ if (m_texture_id)
+ glDeleteTextures(1, &m_texture_id);
+}
+
+
+void EtcTexture::bind()
+{
+ if (m_texture_id) {
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+ return;
+ }
+
+#ifdef ETC_DEBUG
+ printf("EtcTextureProvider: about to update that texture...\n");
+#endif
+
+ glGenTextures(1, &m_texture_id);
+
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+
+#ifdef ETC_DEBUG
+ qDebug() << "glCompressedTexImage2D, width: " << m_size.width() << "height" << m_size.height() <<
+ "paddedWidth: " << m_paddedSize.width() << "paddedHeight: " << m_paddedSize.height();
+#endif
+
+ const QGLContext *ctx = QGLContext::currentContext();
+ Q_ASSERT(ctx != 0);
+ ctx->functions()->glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_ETC1_RGB8_OES,
+ m_size.width(), m_size.height(), 0,
+ (m_paddedSize.width() * m_paddedSize.height()) >> 1,
+ m_data.data() + 16);
+
+ // Gracefully fail in case of an error...
+ GLuint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ qDebug () << "glCompressedTexImage2D for compressed texture failed, error: " << error;
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures(1, &m_texture_id);
+ m_texture_id = 0;
+ return;
+ }
+ updateBindOptions(true);
+}
+
+QSize EtcTexture::textureSize() const
+{
+ return m_size;
+}
+
+QSGTexture *QEtcProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ Q_UNUSED(requestedSize);
+ EtcTexture *ret = 0;
+
+ size->setHeight(0);
+ size->setWidth(0);
+
+ QFile file(id);
+#ifdef ETC_DEBUG
+ qDebug() << "requestTexture opening file: " << id;
+#endif
+ if (file.open(QIODevice::ReadOnly)) {
+ ret = new EtcTexture();
+ ret->m_data = file.readAll();
+ if (!ret->m_data.isEmpty()) {
+ ETCHeader *pETCHeader = NULL;
+ pETCHeader = (ETCHeader *)ret->m_data.data();
+ size->setHeight(getHeight(pETCHeader));
+ size->setWidth(getWidth(pETCHeader));
+ ret->m_size = *size;
+ ret->m_paddedSize.setHeight(getPaddedHeight(pETCHeader));
+ ret->m_paddedSize.setWidth(getPaddedWidth(pETCHeader));
+ }
+ else {
+ free (ret);
+ ret = 0;
+ }
+ }
+
+#ifdef ETC_DEBUG
+ if (ret)
+ qDebug() << "requestTexture returning: " << ret->m_data.length() << ", bytes; width: " << size->width() << ", height: " << size->height();
+ else
+ qDebug () << "File not found.";
+#endif
+
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/etcprovider/qetcprovider.h b/src/imports/etcprovider/qetcprovider.h
new file mode 100644
index 0000000000..ab79bd480d
--- /dev/null
+++ b/src/imports/etcprovider/qetcprovider.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QETCPROVIDER_H
+#define QETCPROVIDER_H
+
+#include <qgl.h>
+#include <QDeclarativeImageProvider>
+#include <QSGTexture>
+#include <QDeclarativeEngine>
+#include <QDeclarativeContext>
+#include <QFileInfo>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+// #define ETC_DEBUG
+
+class EtcTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ EtcTexture();
+ ~EtcTexture();
+
+ void bind();
+ QSize textureSize() const;
+
+ int textureId() const { return m_texture_id; }
+
+ void setImage(const QImage &image) { Q_UNUSED(image); }
+
+ bool hasAlphaChannel() const { return false; }
+ bool hasMipmaps() const { return false; }
+
+ QByteArray m_data;
+ QSize m_size;
+ QSize m_paddedSize;
+ GLuint m_texture_id;
+};
+
+class QEtcProvider : public QDeclarativeImageProvider
+{
+public:
+ QEtcProvider()
+ : QDeclarativeImageProvider(QDeclarativeImageProvider::Texture)
+ {
+#ifdef ETC_DEBUG
+ qDebug () << "Creating QEtcProvider.";
+#endif
+ }
+ QSGTexture *requestTexture(const QString &id, QSize *size, const QSize &requestedSize);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QETCPROVIDER_H
diff --git a/src/imports/etcprovider/qmldir b/src/imports/etcprovider/qmldir
new file mode 100644
index 0000000000..f731f581a3
--- /dev/null
+++ b/src/imports/etcprovider/qmldir
@@ -0,0 +1 @@
+plugin qmletcproviderplugin
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index 5e50b08da8..6704b3ae3c 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -1,4 +1,4 @@
TEMPLATE = subdirs
-SUBDIRS += folderlistmodel particles gestures
+SUBDIRS += folderlistmodel particles gestures inputcontext etcprovider
diff --git a/src/imports/inputcontext/declarativeinputcontext.cpp b/src/imports/inputcontext/declarativeinputcontext.cpp
new file mode 100644
index 0000000000..b52f6ecbba
--- /dev/null
+++ b/src/imports/inputcontext/declarativeinputcontext.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "declarativeinputcontext.h"
+
+#include "inputcontextmodule.h"
+#include "inputcontextfilter.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+DeclarativeInputContext::DeclarativeInputContext(QObject *parent)
+ : QInputContext(parent)
+ , m_module(0)
+{
+}
+
+DeclarativeInputContext::~DeclarativeInputContext()
+{
+}
+
+bool DeclarativeInputContext::isComposing() const
+{
+ return m_module && !m_module->preeditText().isEmpty();
+}
+
+QString DeclarativeInputContext::identifierName()
+{
+ return QLatin1String("Qt.labs.inputcontext/1.0");
+}
+
+QString DeclarativeInputContext::language()
+{
+ return QString();
+}
+
+void DeclarativeInputContext::setFocusWidget(QWidget *widget)
+{
+ QInputContext::setFocusWidget(widget);
+
+ if (m_module)
+ m_module->setFocusWidget(widget);
+}
+
+void DeclarativeInputContext::mouseHandler(int x, QMouseEvent *event)
+{
+ if (!m_mouseHandlers.isEmpty()) {
+ InputContextMouseEvent me(*event);
+ foreach (InputContextMouseHandler *handler, m_mouseHandlers) {
+ handler->processEvent(event->type(), x, &me);
+ if (me.isAccepted()) {
+ event->setAccepted(true);
+ return;
+ }
+ }
+ }
+}
+
+bool DeclarativeInputContext::filterMouseEvent(const QMouseEvent *event)
+{
+ if (!m_mouseFilters.isEmpty()) {
+ InputContextMouseEvent me(*event);
+ foreach (InputContextMouseFilter *filter, m_mouseFilters) {
+ filter->processEvent(event->type(), &me);
+ if (me.isAccepted())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DeclarativeInputContext::filterKeyEvent(const QKeyEvent *event)
+{
+ if (!m_keyFilters.isEmpty()) {
+ InputContextKeyEvent ke(*event);
+ foreach (InputContextKeyFilter *filter, m_keyFilters) {
+ filter->processEvent(event->type(), &ke);
+ if (ke.isAccepted())
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DeclarativeInputContext::filterEvent(const QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::RequestSoftwareInputPanel:
+ if (m_module)
+ m_module->setVisible(true);
+ return true;
+ case QEvent::CloseSoftwareInputPanel:
+ if (m_module)
+ m_module->setVisible(false);
+ return true;
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ return filterMouseEvent(static_cast<const QMouseEvent *>(event));
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ return filterKeyEvent(static_cast<const QKeyEvent *>(event));
+ default:
+ return false;
+ }
+}
+
+void DeclarativeInputContext::reset()
+{
+ if (m_module)
+ m_module->commit();
+}
+
+void DeclarativeInputContext::update()
+{
+ if (m_module)
+ m_module->update();
+}
+
+void DeclarativeInputContext::setModule(InputContextModule *module)
+{
+ m_module = module;
+}
+
+void DeclarativeInputContext::registerMouseHandler(InputContextMouseHandler *handler)
+{
+ connect(handler, SIGNAL(destroyed(QObject*)), this, SLOT(mouseHandlerDestroyed(QObject*)));
+ m_mouseHandlers.append(handler);
+}
+
+void DeclarativeInputContext::registerMouseFilter(InputContextMouseFilter *filter)
+{
+ connect(filter, SIGNAL(destroyed(QObject*)), this, SLOT(mouseFilterDestroyed(QObject*)));
+ m_mouseFilters.append(filter);
+}
+
+void DeclarativeInputContext::registerKeyFilter(InputContextKeyFilter *filter)
+{
+ connect(filter, SIGNAL(destroyed(QObject*)), this, SLOT(keyFilterDestroyed(QObject*)));
+ m_keyFilters.append(filter);
+}
+
+void DeclarativeInputContext::mouseHandlerDestroyed(QObject *handler)
+{
+ m_mouseHandlers.removeAll(static_cast<InputContextMouseHandler *>(handler));
+}
+
+void DeclarativeInputContext::mouseFilterDestroyed(QObject *filter)
+{
+ m_mouseFilters.removeAll(static_cast<InputContextMouseFilter *>(filter));
+}
+
+void DeclarativeInputContext::keyFilterDestroyed(QObject *filter)
+{
+ m_keyFilters.removeAll(static_cast<InputContextKeyFilter *>(filter));
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/inputcontext/declarativeinputcontext.h b/src/imports/inputcontext/declarativeinputcontext.h
new file mode 100644
index 0000000000..fff2931f2d
--- /dev/null
+++ b/src/imports/inputcontext/declarativeinputcontext.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DECLARATIVEINPUTCONTEXT_H
+#define DECLARATIVEINPUTCONTEXT_H
+
+#include <QtGui/qinputcontext.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class InputContextKeyFilter;
+class InputContextModule;
+class InputContextMouseFilter;
+class InputContextMouseHandler;
+
+class DeclarativeInputContext : public QInputContext
+{
+ Q_OBJECT
+public:
+ explicit DeclarativeInputContext(QObject *parent = 0);
+ ~DeclarativeInputContext();
+
+ bool isComposing() const;
+
+ QString identifierName();
+ QString language();
+
+ void setFocusWidget(QWidget *widget);
+
+ void mouseHandler(int x, QMouseEvent *event);
+
+ bool filterMouseEvent(const QMouseEvent *event);
+ bool filterKeyEvent(const QKeyEvent *event);
+
+ bool filterEvent(const QEvent *event);
+
+ void reset();
+ void update();
+
+ void setModule(InputContextModule *module);
+
+ void registerMouseHandler(InputContextMouseHandler *handler);
+ void registerMouseFilter(InputContextMouseFilter *filter);
+ void registerKeyFilter(InputContextKeyFilter *filter);
+
+private slots:
+ void mouseHandlerDestroyed(QObject *handler);
+ void mouseFilterDestroyed(QObject *filter);
+ void keyFilterDestroyed(QObject *filter);
+
+private:
+ InputContextModule *m_module;
+ QList<InputContextMouseHandler *> m_mouseHandlers;
+ QList<InputContextMouseFilter *> m_mouseFilters;
+ QList<InputContextKeyFilter *> m_keyFilters;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/inputcontext/inputcontext.pro b/src/imports/inputcontext/inputcontext.pro
new file mode 100755
index 0000000000..9c7ddf4e8b
--- /dev/null
+++ b/src/imports/inputcontext/inputcontext.pro
@@ -0,0 +1,38 @@
+TARGET = qmlinputcontextplugin
+TARGETPATH = Qt/labs/inputcontext
+include(../qimportbase.pri)
+
+QT += declarative script
+
+SOURCES += \
+ declarativeinputcontext.cpp \
+ inputcontextfilter.cpp \
+ inputcontextmodule.cpp \
+ plugin.cpp
+
+HEADERS += \
+ declarativeinputcontext.h \
+ inputcontextfilter.h \
+ inputcontextmodule.h
+
+OTHER_FILES = \
+ qmldir
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/imports/$$TARGETPATH
+target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+qmldir.files += $$PWD/qmldir
+qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+symbian:{
+ TARGET.UID3 = 0x20031E91
+
+ isEmpty(DESTDIR):importFiles.files = qmlinputcontextplugin{QT_LIBINFIX}.dll qmldir
+ else:importFiles.files = $$DESTDIR/qmlinputcontextplugin$${QT_LIBINFIX}.dll qmldir
+ importFiles.path = $$QT_IMPORTS_BASE_DIR/$$TARGETPATH
+
+ DEPLOYMENT = importFiles
+}
+
+INSTALLS += target qmldir
+
diff --git a/src/imports/inputcontext/inputcontextfilter.cpp b/src/imports/inputcontext/inputcontextfilter.cpp
new file mode 100644
index 0000000000..c0c6c09ed9
--- /dev/null
+++ b/src/imports/inputcontext/inputcontextfilter.cpp
@@ -0,0 +1,352 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "inputcontextfilter.h"
+
+#include "declarativeinputcontext.h"
+
+#include <QtGui/qapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass KeyEvent InputContextKeyEvent
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ \brief The KeyEvent object provides information about a key event.
+*/
+
+/*!
+ \qmlproperty int KeyEvent::key
+
+ This property holds the key code of the key that was pressed or released.
+*/
+
+/*!
+ \qmlproperty string KeyEvent::text
+
+ This property holds the text that this key generated.
+*/
+
+/*!
+ \qmlproperty int KeyEvent::modifiers
+
+ This property holds the keyboard modifier flags that existed immediately
+ after this event was generated.
+*/
+
+/*!
+ \qmlproperty bool KeyEvent::autoRepeat
+
+ This property returns true if this event comes from an auto repeating key
+ press, on the initial key press this returns false.
+*/
+
+/*!
+ \qmlproperty int KeyEvent::count
+
+ This property holds the number of keys involved in this event. If the
+ \l text is non-empty this is the length of the string.
+*/
+
+/*!
+ \qmlproperty bool KeyEvent::accepted
+
+ This property holds whether the event was accepted.
+
+ This is false by default.
+*/
+
+/*!
+ \qmlclass MouseEvent InputContextMouseEvent
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ \brief The MouseEvent object provides information about a mouse event.
+
+*/
+
+/*!
+ \qmlproperty int MouseEvent::x
+
+ This property holds the x position in scene coordinates of the mouse cursor
+ at the time of the event.
+*/
+
+/*!
+ \qmlproperty int MouseEvent::y
+
+ This property holds the y position in scene coordinates of the mouse cursor
+ at the time of the event.
+*/
+
+/*!
+ \qmlproperty enum MouseEvent::button
+
+ This property holds the button that caused the event.
+*/
+
+/*!
+ \qmlproperty int MouseEvent::buttons
+
+ This property holds the button state when the event was generated.
+*/
+
+/*!
+ \qmlproperty int MouseEvent::modifiers
+
+ This property holds the keyboard modifier flags that existed when the event
+ was generated.
+*/
+
+/*!
+ \qmlproperty bool MouseEvent::accepted
+
+ This property holds whether the event was accepted.
+
+ This is false by default.
+*/
+
+/*!
+ \qmlclass MouseHandler InputContextMouseHandler
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ \brief The MouseHandler item provides mouse event handling for input methods.
+
+ The MouseHandler item can be used to handle mouse press, release, move and
+ double click events within or surrounding the pre-edit text.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onPressed(int cursor, MouseEvent mouse)
+
+ This handler is called when there is a press. The \a cursor parameter is
+ the text cursor position of the press within the pre-edit text, and the
+ \a mouse parameter holds information about the press.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onReleased(int cursor, MouseEvent mouse)
+
+ This handler is called when there is a release. The \a cursor parameter is
+ the text cursor position of the press within the pre-edit text, and the
+ \a mouse parameter holds information about the release.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onPositionChanged(int cursor, MouseEvent mouse)
+
+ This handler is called when the mouse position changes.
+
+ The \a cursor parameter is the text cursor position of the press within
+ the pre-edit text, and the \a mouse parameter holds information about the
+ position change.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onDoubleClicked(int cursor, MouseEvent mouse)
+
+ This handler is called when there is a double-click. The \a cursor
+ parameter is the text cursor position of the press within the pre-edit
+ text, and the \a mouse parameter holds information about the double-click.
+*/
+
+InputContextMouseHandler::InputContextMouseHandler(QObject *parent)
+ : QObject(parent)
+{
+ if (DeclarativeInputContext *context = qobject_cast<DeclarativeInputContext *>(
+ qApp->inputContext())) {
+ context->registerMouseHandler(this);
+ }
+}
+
+void InputContextMouseHandler::processEvent(QEvent::Type type, int cursor, InputContextMouseEvent *event)
+{
+ switch (type) {
+ case QEvent::MouseButtonPress:
+ emit pressed(cursor, event);
+ break;
+ case QEvent::MouseButtonRelease:
+ emit released(cursor, event);
+ break;
+ case QEvent::MouseButtonDblClick:
+ emit doubleClicked(cursor, event);
+ break;
+ case QEvent::MouseMove:
+ emit positionChanged(cursor, event);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ \qmlclass MouseFilter InputContextMouseFilter
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ \brief The MouseFilter item provides mouse event filtering for input methods.
+
+ The MouseFilter item can be used to filter mouse press, release, move and
+ double click events received by the item with active focus.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onPressed(MouseEvent mouse)
+
+ This handler is called when there is a press. The \a mouse parameter holds
+ information about the press.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onReleased(MouseEvent mouse)
+
+ This handler is called when there is a release. The \a mouse parameter
+ holds information about the release.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onPositionChanged(MouseEvent mouse)
+
+ This handler is called when the mouse position changes.
+
+ The \a mouse parameter holds information about the position change.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onDoubleClicked(MouseEvent mouse)
+
+ This handler is called when there is a double-click. The \a mouse
+ parameter holds information about the double-click.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+InputContextMouseFilter::InputContextMouseFilter(QObject *parent)
+ : QObject(parent)
+{
+ if (DeclarativeInputContext *context = qobject_cast<DeclarativeInputContext *>(
+ qApp->inputContext())) {
+ context->registerMouseFilter(this);
+ }
+}
+
+void InputContextMouseFilter::processEvent(QEvent::Type type, InputContextMouseEvent *event)
+{
+ switch (type) {
+ case QEvent::MouseButtonPress:
+ emit pressed(event);
+ break;
+ case QEvent::MouseButtonRelease:
+ emit released(event);
+ break;
+ case QEvent::MouseButtonDblClick:
+ emit doubleClicked(event);
+ break;
+ case QEvent::MouseMove:
+ emit positionChanged(event);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ \qmlclass KeyFilter InputContextKeyFilter
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ \brief The KeyFilter item provides key event filtering for input methods.
+
+ The KeyFilter item can be used to filter key press and releae events
+ received by the item with active focus.
+*/
+
+/*!
+ \qmlsignal KeyFilter::onPressed(KeyEvent event)
+
+ This handler is called when there is a key press. The \a event parameter
+ holds information about the press.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+/*!
+ \qmlsignal KeyFilter::onReleased(KeyEvent event)
+
+ This handler is called when there is a key release. The \a event parameter
+ holds information about the release.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+InputContextKeyFilter::InputContextKeyFilter(QObject *parent)
+ : QObject(parent)
+{
+ if (DeclarativeInputContext *context = qobject_cast<DeclarativeInputContext *>(
+ qApp->inputContext())) {
+ context->registerKeyFilter(this);
+ }
+}
+
+void InputContextKeyFilter::processEvent(QEvent::Type type, InputContextKeyEvent *event)
+{
+ switch (type) {
+ case QEvent::KeyPress:
+ emit pressed(event);
+ break;
+ case QEvent::KeyRelease:
+ emit released(event);
+ break;
+ default:
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/inputcontext/inputcontextfilter.h b/src/imports/inputcontext/inputcontextfilter.h
new file mode 100644
index 0000000000..2dd7d5bd67
--- /dev/null
+++ b/src/imports/inputcontext/inputcontextfilter.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INPUTCONTEXTFILTER_H
+#define INPUTCONTEXTFILTER_H
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class InputContextKeyEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int key READ key)
+ Q_PROPERTY(QString text READ text)
+ Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool isAutoRepeat READ isAutoRepeat)
+ Q_PROPERTY(int count READ count)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ InputContextKeyEvent(const QKeyEvent &ke)
+ : event(ke) { event.setAccepted(false); }
+
+ int key() const { return event.key(); }
+ QString text() const { return event.text(); }
+ int modifiers() const { return event.modifiers(); }
+ bool isAutoRepeat() const { return event.isAutoRepeat(); }
+ int count() const { return event.count(); }
+
+ bool isAccepted() { return event.isAccepted(); }
+ void setAccepted(bool accepted) { event.setAccepted(accepted); }
+
+private:
+ QKeyEvent event;
+};
+
+class InputContextMouseEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int x READ x)
+ Q_PROPERTY(int y READ y)
+ Q_PROPERTY(int button READ button)
+ Q_PROPERTY(int buttons READ buttons)
+ Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ InputContextMouseEvent(const QMouseEvent &me)
+ : event(me) { event.setAccepted(false);}
+
+ int x() const { return event.x(); }
+ int y() const { return event.y(); }
+ int button() const { return event.button(); }
+ int buttons() const { return event.buttons(); }
+ int modifiers() const { return event.modifiers(); }
+
+ bool isAccepted() { return event.isAccepted(); }
+ void setAccepted(bool accepted) { event.setAccepted(accepted); }
+
+private:
+ QMouseEvent event;
+};
+
+class InputContextMouseHandler : public QObject
+{
+ Q_OBJECT
+public:
+ InputContextMouseHandler(QObject *parent = 0);
+
+ void processEvent(QEvent::Type type, int cursor, InputContextMouseEvent *event);
+
+signals:
+ void pressed(int cursor, InputContextMouseEvent *mouse);
+ void released(int cursor, InputContextMouseEvent *mouse);
+ void doubleClicked(int cursor, InputContextMouseEvent *mouse);
+ void positionChanged(int cursor, InputContextMouseEvent *mouse);
+};
+
+class InputContextMouseFilter : public QObject
+{
+ Q_OBJECT
+public:
+ InputContextMouseFilter(QObject *parent = 0);
+
+ void processEvent(QEvent::Type type, InputContextMouseEvent *event);
+
+signals:
+ void pressed(InputContextMouseEvent *mouse);
+ void released(InputContextMouseEvent *mouse);
+ void doubleClicked(InputContextMouseEvent *mouse);
+ void positionChanged(InputContextMouseEvent *mouse);
+};
+
+class InputContextKeyFilter : public QObject
+{
+ Q_OBJECT
+public:
+ InputContextKeyFilter(QObject *parent = 0);
+
+ void processEvent(QEvent::Type type, InputContextKeyEvent *event);
+
+signals:
+ void pressed(InputContextKeyEvent *event);
+ void released(InputContextKeyEvent *event);
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(InputContextKeyEvent)
+QML_DECLARE_TYPE(InputContextMouseEvent)
+QML_DECLARE_TYPE(InputContextMouseHandler)
+QML_DECLARE_TYPE(InputContextMouseFilter)
+QML_DECLARE_TYPE(InputContextKeyFilter)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/inputcontext/inputcontextmodule.cpp b/src/imports/inputcontext/inputcontextmodule.cpp
new file mode 100644
index 0000000000..7dc124d083
--- /dev/null
+++ b/src/imports/inputcontext/inputcontextmodule.cpp
@@ -0,0 +1,413 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "inputcontextmodule.h"
+
+#include "declarativeinputcontext.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qtextformat.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlmodule Qt.labs.inputcontext InputContextModule
+
+ \brief The Qt.labs.inputcontext module provides an API for implementing input methods is QML.
+*/
+
+InputContextModule::InputContextModule(QObject *parent)
+ : QObject(parent)
+ , m_inputContext(qobject_cast<DeclarativeInputContext *>(qApp->inputContext()))
+ , m_focusWidget(m_inputContext ? m_inputContext->focusWidget() : 0)
+ , m_visible(false)
+{
+ if (m_inputContext)
+ m_inputContext->setModule(this);
+}
+
+InputContextModule::~InputContextModule()
+{
+ if (m_inputContext)
+ m_inputContext->setModule(0);
+}
+
+/*!
+ \qmlproperty bool focus
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property identifies whether an item that takes text input has active focus.
+*/
+
+bool InputContextModule::hasFocus() const
+{
+ return m_focusWidget != 0;
+}
+
+void InputContextModule::setFocusWidget(QWidget *widget)
+{
+ m_focusWidget = widget;
+
+ if (!m_focusWidget)
+ setVisible(false);
+
+ emit focusChanged();
+}
+
+/*!
+ \qmlproperty bool softwareInputPanelVisible
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property identifies whether the item with focus has requested a
+ software input panel.
+*/
+
+bool InputContextModule::isVisible() const
+{
+ return m_visible;
+}
+
+void InputContextModule::setVisible(bool visible)
+{
+ if (m_visible != visible) {
+ m_visible = visible;
+
+ emit visibleChanged();
+ }
+}
+
+/*!
+ \qmlproperty string preeditText
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the uncommited text that is displayed in the item that
+ has focus.
+*/
+
+QString InputContextModule::preeditText() const
+{
+ return m_preeditText;
+}
+
+void InputContextModule::setPreeditText(const QString &text)
+{
+ if (text != m_preeditText)
+ sendPreedit(text);
+}
+
+/*!
+ \qmlproperty rectangle microFocus
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds a rectangle in scene coordinates around the position
+ of the cursor.
+*/
+
+QRect InputContextModule::microFocus() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImMicroFocus).toRect()
+ : QRect();
+}
+
+/*!
+ \qmlproperty font font
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the font of the text that currently has focus.
+*/
+
+QFont InputContextModule::font() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImFont).value<QFont>()
+ : QFont();
+}
+
+/*!
+ \qmlproperty int cursorPosition
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the position of the text cursor in the
+ \l surroundingText.
+*/
+
+int InputContextModule::cursorPosition() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImCursorPosition).toInt()
+ : 0;
+}
+
+/*!
+ \qmlproperty int anchorPosition
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the position of the selection anchor in the
+ \l surroundingText. If no text is selected this is the same as the
+ \l cursorPosition.
+*/
+
+int InputContextModule::anchorPosition() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImAnchorPosition).toInt()
+ : 0;
+}
+
+/*!
+ \qmlproperty int maximumTextLength
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the maximum number of characters that the item with
+ focus can hold. If there is no limit -1 is returned.
+*/
+
+int InputContextModule::maximumTextLength() const
+{
+ QVariant length;
+ if (m_focusWidget)
+ length = m_focusWidget->inputMethodQuery(Qt::ImMaximumTextLength);
+ return length.isValid() ? length.toInt() : -1;
+}
+
+/*!
+ \qmlproperty string surroundingText
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the plain text around the input area. For example the
+ current paragraph.
+*/
+
+QString InputContextModule::surroundingText() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImSurroundingText).toString()
+ : QString();
+}
+
+/*!
+ \qmlproperty string selectedText
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the currently selected text.
+*/
+
+QString InputContextModule::selectedText() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImCurrentSelection).toString()
+ : QString();
+}
+
+/*!
+ \qmlmethod sendKeyPress(int key, string text, int modifiers, bool autoRepeat)
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This method sends a key press event to the item that currently has focus.
+
+ Int key is the code for the Qt::Key that the event loop should listen for.
+ If key is 0, the event is not a result of a known key; for example, it may
+ be the result of a compose sequence or keyboard macro. The modifiers holds
+ the keyboard modifiers, and the given text is the Unicode text that the key
+ generated. If autorep is true, isAutoRepeat() will be true. count is the
+ number of keys involved in the event.
+*/
+void InputContextModule::sendKeyPress(
+ int key, const QString &text, int modifiers, bool autoRepeat, int count)
+{
+ if (m_focusWidget) {
+ QKeyEvent event(
+ QEvent::KeyPress, key, Qt::KeyboardModifiers(modifiers), text, autoRepeat, count);
+ if (!m_inputContext || !m_inputContext->filterKeyEvent(&event))
+ QApplication::sendEvent(m_focusWidget, &event);
+ }
+}
+
+/*!
+ \qmlmethod sendKeyRelease(int key, string text, int modifiers)
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This method sends a key release event to the item that currently has focus.
+
+ Int key is the code for the Qt::Key that the event loop should listen for.
+ If key is 0, the event is not a result of a known key; for example, it may
+ be the result of a compose sequence or keyboard macro. The modifiers holds
+ the keyboard modifiers, and the given text is the Unicode text that the key
+ generated. count is the number of keys involved in the event.
+*/
+void InputContextModule::sendKeyRelease(int key, const QString &text, int modifiers, int count)
+{
+ if (m_focusWidget) {
+ QKeyEvent event(
+ QEvent::KeyRelease, key, Qt::KeyboardModifiers(modifiers), text, false, count);
+ if (!m_inputContext || !m_inputContext->filterKeyEvent(&event))
+ QApplication::sendEvent(m_focusWidget, &event);
+ }
+}
+
+/*!
+ \qmlmethod sendPreedit(string text, int cursor = -1)
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ Sends a pre-edit event to the item with active focus.
+
+ This will set \l preeditText to \a text, and position the text \a cursor
+ within the pre-edit text. If the value of cursor is -1 the cursor will be
+ positioned at the end of the pre-edit text.
+*/
+void InputContextModule::sendPreedit(const QString &text, int cursor)
+{
+ const QString preedit = m_preeditText;
+ m_preeditText = text;
+
+ if (m_inputContext) {
+ QList<QInputMethodEvent::Attribute> attributes;
+
+ if (cursor >= 0 && cursor <= text.length()) {
+ attributes.append(QInputMethodEvent::Attribute(
+ QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
+ } else {
+ cursor = text.length();
+ }
+
+ if (cursor > 0) {
+ attributes.append(QInputMethodEvent::Attribute(
+ QInputMethodEvent::TextFormat,
+ 0,
+ cursor,
+ m_inputContext->standardFormat(QInputContext::PreeditFormat)));
+ }
+ if (cursor < text.length()) {
+ attributes.append(QInputMethodEvent::Attribute(
+ QInputMethodEvent::TextFormat,
+ cursor,
+ text.length(),
+ m_inputContext->standardFormat(QInputContext::SelectionFormat)));
+ }
+
+ m_inputContext->sendEvent(QInputMethodEvent(text, attributes));
+ }
+
+ if (m_preeditText != preedit)
+ emit preeditTextChanged();
+}
+
+
+/*!
+ \qmlmethod commit()
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ Commits \l preeditText to the item with active focus.
+*/
+void InputContextModule::commit()
+{
+ // Create an explicit copy of m_preeditText as the reference value is cleared before sending
+ // the event.
+ commit(QString(m_preeditText));
+}
+
+/*!
+ \qmlmethod commit(string)
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ Commits \a text to the item with active focus and clears the current
+ \l preeditText. The text will be inserted into the \l surroundingText at a
+ position \a replacementStart relative to the \l cursorPosition and will
+ replace \a replacementLength characters.
+*/
+void InputContextModule::commit(const QString &text, int replacementStart, int replacementLength)
+{
+ const QString preedit = m_preeditText;
+ m_preeditText.clear();
+
+ if (m_inputContext) {
+ QInputMethodEvent inputEvent;
+ inputEvent.setCommitString(text, replacementStart, replacementLength);
+ m_inputContext->sendEvent(inputEvent);
+ }
+
+ if (m_preeditText != preedit)
+ emit preeditTextChanged();
+}
+
+/*!
+ \qmlmethod clear()
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ Clears the current \l preeditText.
+*/
+void InputContextModule::clear()
+{
+ const QString preedit = m_preeditText;
+ m_preeditText.clear();
+
+ if (m_inputContext)
+ m_inputContext->sendEvent(QInputMethodEvent());
+
+ if (m_preeditText != preedit)
+ emit preeditTextChanged();
+}
+
+void InputContextModule::update()
+{
+ emit contextUpdated();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/inputcontext/inputcontextmodule.h b/src/imports/inputcontext/inputcontextmodule.h
new file mode 100644
index 0000000000..470701e34e
--- /dev/null
+++ b/src/imports/inputcontext/inputcontextmodule.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INPUTCONTEXTMODULE_H
+#define INPUTCONTEXTMODULE_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qfont.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class DeclarativeInputContext;
+
+class InputContextModule : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool softwareInputPanelVisible READ isVisible WRITE setVisible NOTIFY visibleChanged)
+ Q_PROPERTY(bool focus READ hasFocus NOTIFY focusChanged)
+ Q_PROPERTY(QString preeditText READ preeditText WRITE setPreeditText NOTIFY preeditTextChanged)
+ Q_PROPERTY(QRect microFocus READ microFocus NOTIFY contextUpdated)
+ Q_PROPERTY(QFont font READ font NOTIFY contextUpdated)
+ Q_PROPERTY(int cursorPosition READ cursorPosition NOTIFY contextUpdated)
+ Q_PROPERTY(int anchorPosition READ anchorPosition NOTIFY contextUpdated)
+ Q_PROPERTY(int maximumTextLength READ maximumTextLength NOTIFY contextUpdated)
+ Q_PROPERTY(QString surroundingText READ surroundingText NOTIFY contextUpdated)
+ Q_PROPERTY(QString selectedText READ selectedText NOTIFY contextUpdated)
+public:
+ explicit InputContextModule(QObject *parent = 0);
+ ~InputContextModule();
+
+ bool hasFocus() const;
+ void setFocusWidget(QWidget *widget);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ QString preeditText() const;
+ void setPreeditText(const QString &text);
+
+ QRect microFocus() const;
+ QFont font() const;
+ int cursorPosition() const;
+ int anchorPosition() const;
+ int maximumTextLength() const;
+ QString surroundingText() const;
+ QString selectedText() const;
+
+ Q_INVOKABLE void sendKeyPress(
+ int key, const QString &text, int modifiers = 0, bool autoRepeat = false, int count = 1);
+ Q_INVOKABLE void sendKeyRelease(int key, const QString &text, int modifiers = 0, int count = 1);
+
+ Q_INVOKABLE void sendPreedit(const QString &text, int cursor = -1);
+
+ Q_INVOKABLE void commit();
+ Q_INVOKABLE void commit(const QString &text, int replacementStart = 0, int replacementEnd = 0);
+
+ Q_INVOKABLE void clear();
+
+ void update();
+
+signals:
+ void preeditTextChanged();
+ void visibleChanged();
+ void contextUpdated();
+ void focusChanged();
+
+private:
+ QString m_preeditText;
+ DeclarativeInputContext *m_inputContext;
+ QWidget *m_focusWidget;
+ bool m_visible;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/inputcontext/plugin.cpp b/src/imports/inputcontext/plugin.cpp
new file mode 100644
index 0000000000..1f4bcde673
--- /dev/null
+++ b/src/imports/inputcontext/plugin.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "declarativeinputcontext.h"
+#include "inputcontextfilter.h"
+#include "inputcontextmodule.h"
+
+#include <QtDeclarative/qdeclarativeextensionplugin.h>
+#include <QtGui/qapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+static QObject *createContext(QDeclarativeEngine *, QScriptEngine *)
+{
+ return new InputContextModule;
+}
+
+class InputContextQmlPlugin : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+public:
+ virtual void registerTypes(const char *uri)
+ {
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.inputcontext"));
+
+ qApp->setInputContext(new DeclarativeInputContext);
+
+ qmlRegisterModuleApi(uri, 1, 0, createContext);
+ qmlRegisterType<InputContextMouseHandler>(uri, 1, 0, "MouseHandler");
+ qmlRegisterType<InputContextMouseFilter>(uri, 1, 0, "MouseFilter");
+ qmlRegisterType<InputContextKeyFilter>(uri, 1, 0, "KeyFilter");
+ qmlRegisterType<InputContextMouseEvent>();
+ qmlRegisterType<InputContextKeyEvent>();
+ }
+};
+
+QT_END_NAMESPACE
+
+Q_EXPORT_PLUGIN2(InputContext, QT_PREPEND_NAMESPACE(InputContextQmlPlugin));
+
+#include "plugin.moc"
diff --git a/src/imports/inputcontext/qmldir b/src/imports/inputcontext/qmldir
new file mode 100644
index 0000000000..3fb65a6e0e
--- /dev/null
+++ b/src/imports/inputcontext/qmldir
@@ -0,0 +1 @@
+plugin qmlinputcontextplugin
diff --git a/src/imports/particles/qdeclarativeparticles.cpp b/src/imports/particles/V1/qdeclarativeparticles.cpp
index f54152c054..f54152c054 100644
--- a/src/imports/particles/qdeclarativeparticles.cpp
+++ b/src/imports/particles/V1/qdeclarativeparticles.cpp
diff --git a/src/imports/particles/qdeclarativeparticles_p.h b/src/imports/particles/V1/qdeclarativeparticles_p.h
index 4ffdbbab9e..4ffdbbab9e 100644
--- a/src/imports/particles/qdeclarativeparticles_p.h
+++ b/src/imports/particles/V1/qdeclarativeparticles_p.h
diff --git a/src/imports/particles/angledvector.cpp b/src/imports/particles/angledvector.cpp
new file mode 100644
index 0000000000..85b5ed7472
--- /dev/null
+++ b/src/imports/particles/angledvector.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "angledvector.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+const qreal CONV = 0.017453292519943295;
+AngledVector::AngledVector(QObject *parent) :
+ VaryingVector(parent)
+ , m_angle(0)
+ , m_magnitude(0)
+ , m_angleVariation(0)
+ , m_magnitudeVariation(0)
+{
+
+}
+
+const QPointF &AngledVector::sample(const QPointF &from)
+{
+ //TODO: Faster
+ qreal theta = m_angle*CONV - m_angleVariation*CONV + rand()/float(RAND_MAX) * m_angleVariation*CONV * 2;
+ qreal mag = m_magnitude- m_magnitudeVariation + rand()/float(RAND_MAX) * m_magnitudeVariation * 2;
+ m_ret.setX(mag * cos(theta));
+ m_ret.setY(mag * sin(theta));
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/angledvector.h b/src/imports/particles/angledvector.h
new file mode 100644
index 0000000000..ac78059e43
--- /dev/null
+++ b/src/imports/particles/angledvector.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANGLEDVECTOR_H
+#define ANGLEDVECTOR_H
+#include "varyingvector.h"
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class AngledVector : public VaryingVector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+ 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)
+public:
+ explicit AngledVector(QObject *parent = 0);
+ const QPointF &sample(const QPointF &from);
+ qreal angle() const
+ {
+ return m_angle;
+ }
+
+ qreal magnitude() const
+ {
+ return m_magnitude;
+ }
+
+ qreal angleVariation() const
+ {
+ return m_angleVariation;
+ }
+
+ qreal magnitudeVariation() const
+ {
+ return m_magnitudeVariation;
+ }
+
+signals:
+
+ void angleChanged(qreal arg);
+
+ void magnitudeChanged(qreal arg);
+
+ void angleVariationChanged(qreal arg);
+
+ void magnitudeVariationChanged(qreal arg);
+
+public slots:
+void setAngle(qreal arg)
+{
+ if (m_angle != arg) {
+ m_angle = arg;
+ emit angleChanged(arg);
+ }
+}
+
+void setMagnitude(qreal arg)
+{
+ if (m_magnitude != arg) {
+ m_magnitude = arg;
+ emit magnitudeChanged(arg);
+ }
+}
+
+void setAngleVariation(qreal arg)
+{
+ if (m_angleVariation != arg) {
+ m_angleVariation = arg;
+ emit angleVariationChanged(arg);
+ }
+}
+
+void setMagnitudeVariation(qreal arg)
+{
+ if (m_magnitudeVariation != arg) {
+ m_magnitudeVariation = arg;
+ emit magnitudeVariationChanged(arg);
+ }
+}
+
+private:
+qreal m_angle;
+qreal m_magnitude;
+qreal m_angleVariation;
+qreal m_magnitudeVariation;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ANGLEDVECTOR_H
diff --git a/src/imports/particles/attractoraffector.cpp b/src/imports/particles/attractoraffector.cpp
new file mode 100644
index 0000000000..847cb2c471
--- /dev/null
+++ b/src/imports/particles/attractoraffector.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "attractoraffector.h"
+#include <cmath>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+AttractorAffector::AttractorAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_strength(0.0), m_x(0), m_y(0)
+{
+}
+
+bool AttractorAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ if(m_strength == 0.0)
+ return false;
+ qreal dx = m_x - d->curX();
+ qreal dy = m_y - d->curY();
+ qreal r = sqrt((dx*dx) + (dy*dy));
+ qreal theta = atan2(dy,dx);
+ qreal ds = (m_strength / r) * dt;
+ dx = ds * cos(theta);
+ dy = ds * sin(theta);
+ d->setInstantaneousSX(d->pv.sx + dx);
+ d->setInstantaneousSY(d->pv.sy + dy);
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/attractoraffector.h b/src/imports/particles/attractoraffector.h
new file mode 100644
index 0000000000..f41e9ad5e4
--- /dev/null
+++ b/src/imports/particles/attractoraffector.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ATTRACTORAFFECTOR_H
+#define ATTRACTORAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class AttractorAffector : public ParticleAffector
+{
+ Q_OBJECT
+ //Like Gravitational singularity, but linear to distance instead of quadratic
+ //And affects ds/dt, not da/dt
+ Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+public:
+ explicit AttractorAffector(QSGItem *parent = 0);
+
+ qreal strength() const
+ {
+ return m_strength;
+ }
+
+ qreal x() const
+ {
+ return m_x;
+ }
+
+ qreal y() const
+ {
+ return m_y;
+ }
+
+signals:
+
+ void strengthChanged(qreal arg);
+
+ void xChanged(qreal arg);
+
+ void yChanged(qreal arg);
+
+public slots:
+void setStrength(qreal arg)
+{
+ if (m_strength != arg) {
+ m_strength = arg;
+ emit strengthChanged(arg);
+ }
+}
+
+void setX(qreal arg)
+{
+ if (m_x != arg) {
+ m_x = arg;
+ emit xChanged(arg);
+ }
+}
+
+void setY(qreal arg)
+{
+ if (m_y != arg) {
+ m_y = arg;
+ emit yChanged(arg);
+ }
+}
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+private:
+qreal m_strength;
+qreal m_x;
+qreal m_y;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ATTRACTORAFFECTOR_H
diff --git a/src/imports/particles/coloredparticle.cpp b/src/imports/particles/coloredparticle.cpp
new file mode 100644
index 0000000000..7d0ec4cb0a
--- /dev/null
+++ b/src/imports/particles/coloredparticle.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include "coloredparticle.h"
+#include "particleemitter.h"
+#include <QGLFunctions>
+#include <qsgengine.h>
+
+QT_BEGIN_NAMESPACE
+
+class ParticleTrailsMaterial : public QSGMaterial
+{
+public:
+ ParticleTrailsMaterial()
+ : timestamp(0)
+ {
+ setFlag(Blending, true);
+ }
+
+ ~ParticleTrailsMaterial()
+ {
+ delete texture;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const ParticleTrailsMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+
+ qreal timestamp;
+};
+
+
+class ParticleTrailsMaterialData : public QSGMaterialShader
+{
+public:
+ ParticleTrailsMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/trailsvertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/trailsfragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ m_program.setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ ParticleTrailsMaterial *m = static_cast<ParticleTrailsMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);
+ m->texture->bind();
+
+ m_program.setUniformValue(m_opacity_id, state.opacity());
+ m_program.setUniformValue(m_timestamp_id, (float) m->timestamp);
+
+ if (state.isMatrixDirty())
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = m_program.uniformLocation("matrix");
+ m_opacity_id = m_program.uniformLocation("opacity");
+ m_timestamp_id = m_program.uniformLocation("timestamp");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ "vColor",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float ParticleTrailsMaterialData::chunkOfBytes[1024];
+
+
+QSGMaterialShader *ParticleTrailsMaterial::createShader() const
+{
+ return new ParticleTrailsMaterialData;
+}
+
+
+class ParticleTrailsMaterialCT : public ParticleTrailsMaterial
+{
+public:
+ ParticleTrailsMaterialCT()
+ {
+ }
+
+ ~ParticleTrailsMaterialCT()
+ {
+ delete colortable;
+ delete sizetable;
+ delete opacitytable;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+
+ QSGTexture *colortable;
+ QSGTexture *sizetable;
+ QSGTexture *opacitytable;
+};
+
+
+class ParticleTrailsMaterialDataCT : public ParticleTrailsMaterialData
+{
+public:
+ ParticleTrailsMaterialDataCT()
+ : ParticleTrailsMaterialData(":resources/ctvertex.shader", ":resources/ctfragment.shader")
+ {
+ }
+
+ bool isColorTable() const { return true; }
+
+ virtual void initialize() {
+ ParticleTrailsMaterialData::initialize();
+ m_colortable_id = m_program.uniformLocation("colortable");
+ m_sizetable_id = m_program.uniformLocation("sizetable");
+ m_opacitytable_id = m_program.uniformLocation("opacitytable");
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *current, QSGMaterial *old)
+ {
+ // Bind the texture to unit 1 before calling the base class, so that the
+ // base class can set active texture back to 0.
+ ParticleTrailsMaterialCT *m = static_cast<ParticleTrailsMaterialCT *>(current);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE1);
+ m->colortable->bind();
+ m_program.setUniformValue(m_colortable_id, 1);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE2);
+ m->sizetable->bind();
+ m_program.setUniformValue(m_sizetable_id, 2);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE3);
+ m->opacitytable->bind();
+ m_program.setUniformValue(m_opacitytable_id, 3);
+
+ ParticleTrailsMaterialData::updateState(state, current, old);
+ }
+
+ int m_colortable_id;
+ int m_sizetable_id;
+ int m_opacitytable_id;
+};
+
+
+QSGMaterialShader *ParticleTrailsMaterialCT::createShader() const
+{
+ return new ParticleTrailsMaterialDataCT;
+}
+
+ColoredParticle::ColoredParticle(QSGItem* parent)
+ : ParticleType(parent)
+ , m_do_reset(false)
+ , m_color(Qt::white)
+ , m_color_variation(0.5)
+ , m_node(0)
+ , m_material(0)
+ , m_alphaVariation(0.0)
+ , m_alpha(1.0)
+ , m_redVariation(0.0)
+ , m_greenVariation(0.0)
+ , m_blueVariation(0.0)
+{
+ setFlag(ItemHasContents);
+}
+
+void ColoredParticle::setImage(const QUrl &image)
+{
+ if (image == m_image_name)
+ return;
+ m_image_name = image;
+ emit imageChanged();
+ reset();
+}
+
+
+void ColoredParticle::setColortable(const QUrl &table)
+{
+ if (table == m_colortable_name)
+ return;
+ m_colortable_name = table;
+ emit colortableChanged();
+ reset();
+}
+
+void ColoredParticle::setSizetable(const QUrl &table)
+{
+ if (table == m_sizetable_name)
+ return;
+ m_sizetable_name = table;
+ emit sizetableChanged();
+ reset();
+}
+
+void ColoredParticle::setOpacitytable(const QUrl &table)
+{
+ if (table == m_opacitytable_name)
+ return;
+ m_opacitytable_name = table;
+ emit opacitytableChanged();
+ reset();
+}
+
+void ColoredParticle::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ emit colorChanged();
+ //m_system->pleaseReset();//XXX
+}
+
+void ColoredParticle::setColorVariation(qreal var)
+{
+ if (var == m_color_variation)
+ return;
+ m_color_variation = var;
+ emit colorVariationChanged();
+ //m_system->pleaseReset();//XXX
+}
+
+void ColoredParticle::setCount(int c)
+{
+ ParticleType::setCount(c);
+ m_pleaseReset = true;
+}
+
+void ColoredParticle::reset()
+{
+ ParticleType::reset();
+ m_pleaseReset = true;
+}
+
+static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_UNSIGNED_BYTE } // Colors
+};
+
+static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
+{
+ 5, // Attribute Count
+ (2 + 2 + 4 + 4) * sizeof(float) + 4 * sizeof(uchar),
+ ColoredParticle_Attributes
+};
+
+QSGGeometryNode* ColoredParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ printf("ColoredParticle: Too many particles... \n");
+ return 0;
+ }
+
+ if(m_count <= 0) {
+ printf("ColoredParticle: Too few particles... \n");
+ return 0;
+ }
+
+ QImage image(m_image_name.toLocalFile());
+ if (image.isNull()) {
+ printf("ParticleTrails: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
+ return 0;
+ }
+
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+
+ QSGGeometry *g = new QSGGeometry(ColoredParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ ColoredParticleVertex *vertices = (ColoredParticleVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = 0;
+ vertices[i].y = 0;
+ vertices[i].t = -1;
+ vertices[i].lifeSpan = 0;
+ vertices[i].size = 0;
+ vertices[i].endSize = 0;
+ vertices[i].sx = 0;
+ vertices[i].sy = 0;
+ vertices[i].ax = 0;
+ vertices[i].ay = 0;
+ }
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ QImage colortable(m_colortable_name.toLocalFile());
+ QImage sizetable(m_sizetable_name.toLocalFile());
+ QImage opacitytable(m_opacitytable_name.toLocalFile());
+ if(!colortable.isNull() || !sizetable.isNull() || !opacitytable.isNull()){
+ //using tabled shaders
+ m_material = new ParticleTrailsMaterialCT();
+ if(colortable.isNull())
+ colortable = QImage(":resources/identitytable.png");
+ if(sizetable.isNull())
+ sizetable = QImage(":resources/identitytable.png");
+ if(opacitytable.isNull())
+ opacitytable = QImage(":resources/defaultFadeInOut.png");
+ Q_ASSERT(!colortable.isNull());
+ Q_ASSERT(!sizetable.isNull());
+ Q_ASSERT(!opacitytable.isNull());
+ ParticleTrailsMaterialCT* ct_material = static_cast<ParticleTrailsMaterialCT *>(m_material);
+ ct_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
+ ct_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
+ ct_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
+ }
+
+ if (!m_material)
+ m_material = new ParticleTrailsMaterial();
+
+
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
+QSGNode *ColoredParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node)
+ delete m_node;
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ if(m_system && m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void ColoredParticle::prepareNextFrame()
+{
+ if (m_node == 0){ //TODO: Staggered loading (as emitted)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ }
+ uint timeStamp = m_system->systemSync(this);
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+}
+
+void ColoredParticle::reloadColor(const Color4ub &c, ParticleData* d)
+{
+ ColoredParticleVertices *particles = (ColoredParticleVertices *) m_node->geometry()->vertexData();
+ int pos = particleTypeIndex(d);
+ ColoredParticleVertices &p = particles[pos];
+ p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
+}
+
+void ColoredParticle::vertexCopy(ColoredParticleVertex &b,const ParticleVertex& a)
+{
+ b.x = a.x - m_systemOffset.x();
+ b.y = a.y - m_systemOffset.y();
+ b.t = a.t;
+ b.lifeSpan = a.lifeSpan;
+ b.size = a.size;
+ b.endSize = a.endSize;
+ b.sx = a.sx;
+ b.sy = a.sy;
+ b.ax = a.ax;
+ b.ay = a.ay;
+}
+
+void ColoredParticle::reload(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ ColoredParticleVertices *particles = (ColoredParticleVertices *) m_node->geometry()->vertexData();
+
+ int pos = particleTypeIndex(d);
+
+ ColoredParticleVertices &p = particles[pos];
+
+ //Perhaps we could be more efficient?
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+void ColoredParticle::load(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ //Color initialization
+ // Particle color
+ Color4ub color;
+ qreal redVariation = m_color_variation + m_redVariation;
+ qreal greenVariation = m_color_variation + m_greenVariation;
+ qreal blueVariation = m_color_variation + m_blueVariation;
+ color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
+ color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
+ color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
+ color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
+ ColoredParticleVertices *particles = (ColoredParticleVertices *) m_node->geometry()->vertexData();
+ ColoredParticleVertices &p = particles[particleTypeIndex(d)];
+ p.v1.color = p.v2.color = p.v3.color = p.v4.color = color;
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/coloredparticle.h b/src/imports/particles/coloredparticle.h
new file mode 100644
index 0000000000..446b764941
--- /dev/null
+++ b/src/imports/particles/coloredparticle.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef COLOREDPARTICLE_H
+#define COLOREDPARTICLE_H
+#include "particle.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ParticleTrailsMaterial;
+class QSGGeometryNode;
+
+struct Color4ub {
+ uchar r;
+ uchar g;
+ uchar b;
+ uchar a;
+};
+
+struct ColoredParticleVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ Color4ub color;
+};
+
+struct ColoredParticleVertices {
+ ColoredParticleVertex v1;
+ ColoredParticleVertex v2;
+ ColoredParticleVertex v3;
+ ColoredParticleVertex v4;
+};
+
+class ColoredParticle : public ParticleType
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
+ Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
+ Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
+ Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
+
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ //Stacks (added) with individual colorVariations
+ Q_PROPERTY(qreal colorVariation READ colorVariation WRITE setColorVariation NOTIFY colorVariationChanged)
+ Q_PROPERTY(qreal redVariation READ redVariation WRITE setRedVariation NOTIFY redVariationChanged)
+ Q_PROPERTY(qreal greenVariation READ greenVariation WRITE setGreenVariation NOTIFY greenVariationChanged)
+ Q_PROPERTY(qreal blueVariation READ blueVariation WRITE setBlueVariation NOTIFY blueVariationChanged)
+ //Stacks (multiplies) with the Alpha in the color, mostly here so you can use svg color names (which have full alpha)
+ Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
+
+public:
+ explicit ColoredParticle(QSGItem *parent = 0);
+ virtual ~ColoredParticle(){}
+
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+
+ QUrl image() const { return m_image_name; }
+ void setImage(const QUrl &image);
+
+ QUrl colortable() const { return m_colortable_name; }
+ void setColortable(const QUrl &table);
+
+ QUrl sizetable() const { return m_sizetable_name; }
+ void setSizetable (const QUrl &table);
+
+ QUrl opacitytable() const { return m_opacitytable_name; }
+ void setOpacitytable(const QUrl &table);
+
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color);
+
+ qreal colorVariation() const { return m_color_variation; }
+ void setColorVariation(qreal var);
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+ qreal alphaVariation() const
+ {
+ return m_alphaVariation;
+ }
+
+ qreal alpha() const
+ {
+ return m_alpha;
+ }
+
+ qreal redVariation() const
+ {
+ return m_redVariation;
+ }
+
+ qreal greenVariation() const
+ {
+ return m_greenVariation;
+ }
+
+ qreal blueVariation() const
+ {
+ return m_blueVariation;
+ }
+
+signals:
+
+ void imageChanged();
+ void colortableChanged();
+ void sizetableChanged();
+ void opacitytableChanged();
+
+ void colorChanged();
+ void colorVariationChanged();
+
+ void particleDurationChanged();
+ void alphaVariationChanged(qreal arg);
+
+ void alphaChanged(qreal arg);
+
+ void redVariationChanged(qreal arg);
+
+ void greenVariationChanged(qreal arg);
+
+ void blueVariationChanged(qreal arg);
+
+public slots:
+ void setAlphaVariation(qreal arg)
+ {
+ if (m_alphaVariation != arg) {
+ m_alphaVariation = arg;
+ emit alphaVariationChanged(arg);
+ }
+ }
+
+ void setAlpha(qreal arg)
+ {
+ if (m_alpha != arg) {
+ m_alpha = arg;
+ emit alphaChanged(arg);
+ }
+ }
+
+ void setRedVariation(qreal arg)
+ {
+ if (m_redVariation != arg) {
+ m_redVariation = arg;
+ emit redVariationChanged(arg);
+ }
+ }
+
+ void setGreenVariation(qreal arg)
+ {
+ if (m_greenVariation != arg) {
+ m_greenVariation = arg;
+ emit greenVariationChanged(arg);
+ }
+ }
+
+ void setBlueVariation(qreal arg)
+ {
+ if (m_blueVariation != arg) {
+ m_blueVariation = arg;
+ emit blueVariationChanged(arg);
+ }
+ }
+
+ void reloadColor(const Color4ub &c, ParticleData* d);
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void reset();
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+private:
+ void vertexCopy(ColoredParticleVertex &b,const ParticleVertex& a);
+ bool m_do_reset;
+
+ QUrl m_image_name;
+ QUrl m_colortable_name;
+ QUrl m_sizetable_name;
+ QUrl m_opacitytable_name;
+
+
+ QColor m_color;
+ qreal m_color_variation;
+ qreal m_particleDuration;
+
+ QSGGeometryNode *m_node;
+ ParticleTrailsMaterial *m_material;
+
+ // derived values...
+ int m_last_particle;
+
+ qreal m_render_opacity;
+ qreal m_alphaVariation;
+ qreal m_alpha;
+ qreal m_redVariation;
+ qreal m_greenVariation;
+ qreal m_blueVariation;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // COLOREDPARTICLE_H
diff --git a/src/imports/particles/deformableparticle.cpp b/src/imports/particles/deformableparticle.cpp
new file mode 100644
index 0000000000..2043e12be9
--- /dev/null
+++ b/src/imports/particles/deformableparticle.cpp
@@ -0,0 +1,432 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include "deformableparticle.h"
+#include <QGLFunctions>
+#include <qsgengine.h>
+
+QT_BEGIN_NAMESPACE
+
+const float CONV = 0.017453292519943295;
+class DeformableParticleMaterial : public QSGMaterial
+{
+public:
+ DeformableParticleMaterial()
+ : timestamp(0)
+ {
+ setFlag(Blending, true);
+ }
+
+ ~DeformableParticleMaterial()
+ {
+ delete texture;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const DeformableParticleMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+
+ qreal timestamp;
+};
+
+
+class DeformableParticleMaterialData : public QSGMaterialShader
+{
+public:
+ DeformableParticleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/deformablevertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/deformablefragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ m_program.setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ DeformableParticleMaterial *m = static_cast<DeformableParticleMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);
+ m->texture->bind();
+
+ m_program.setUniformValue(m_opacity_id, state.opacity());
+ m_program.setUniformValue(m_timestamp_id, (float) m->timestamp);
+
+ if (state.isMatrixDirty())
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = m_program.uniformLocation("matrix");
+ m_opacity_id = m_program.uniformLocation("opacity");
+ m_timestamp_id = m_program.uniformLocation("timestamp");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ "vDeformVec",
+ "vRotation",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float DeformableParticleMaterialData::chunkOfBytes[1024];
+
+
+QSGMaterialShader *DeformableParticleMaterial::createShader() const
+{
+ return new DeformableParticleMaterialData;
+}
+
+struct DeformableParticleVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ float xx;
+ float xy;
+ float yx;
+ float yy;
+ float rotation;
+ float autoRotate;//Assume that GPUs prefer floats to bools
+};
+
+struct DeformableParticleVertices {
+ DeformableParticleVertex v1;
+ DeformableParticleVertex v2;
+ DeformableParticleVertex v3;
+ DeformableParticleVertex v4;
+};
+
+
+DeformableParticle::DeformableParticle(QSGItem* parent)
+ : ParticleType(parent)
+ , m_do_reset(false)
+ , m_rotation(0)
+ , m_autoRotation(false)
+ , m_xVector(0)
+ , m_yVector(0)
+ , m_rotationVariation(0)
+{
+ setFlag(ItemHasContents);
+}
+
+void DeformableParticle::setImage(const QUrl &image)
+{
+ if (image == m_image)
+ return;
+ m_image = image;
+ emit imageChanged();
+ reset();
+}
+
+void DeformableParticle::setCount(int c)
+{
+ ParticleType::setCount(c);
+ m_pleaseReset = true;
+}
+
+void DeformableParticle::reset()
+{
+ ParticleType::reset();
+ m_pleaseReset = true;
+}
+
+static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_FLOAT }, // DeformationVectors
+ { 5, 2, GL_FLOAT } // Rotation
+};
+
+static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
+{
+ 6, // Attribute Count
+ (2 + 2 + 4 + 4 + 4 + 2) * sizeof(float),
+ DeformableParticle_Attributes
+};
+
+QSGGeometryNode* DeformableParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ printf("DeformableParticle: Too many particles... \n");
+ return 0;
+ }
+
+ if(m_count <= 0) {
+ printf("DeformableParticle: Too few particles... \n");
+ return 0;
+ }
+
+ QImage image(m_image.toLocalFile());
+ if (image.isNull()) {
+ printf("DeformableParticle: loading image failed... '%s'\n", qPrintable(m_image.toLocalFile()));
+ return 0;
+ }
+
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+
+ QSGGeometry *g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ DeformableParticleVertex *vertices = (DeformableParticleVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = 0;
+ vertices[i].y = 0;
+ vertices[i].t = -1;
+ vertices[i].lifeSpan = 0;
+ vertices[i].size = 0;
+ vertices[i].endSize = 0;
+ vertices[i].sx = 0;
+ vertices[i].sy = 0;
+ vertices[i].ax = 0;
+ vertices[i].ay = 0;
+ vertices[i].xx = 1;
+ vertices[i].xy = 0;
+ vertices[i].yx = 0;
+ vertices[i].yy = 1;
+ vertices[i].rotation = 0;
+ vertices[i].autoRotate = 0;
+ }
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ if (!m_material)
+ m_material = new DeformableParticleMaterial();
+
+
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
+QSGNode *DeformableParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node)
+ delete m_node;
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ if(m_system && m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void DeformableParticle::prepareNextFrame()
+{
+ if (m_node == 0){ //TODO: Staggered loading (as emitted)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ }
+ uint timeStamp = m_system->systemSync(this);
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+
+}
+
+
+void DeformableParticle::vertexCopy(DeformableParticleVertex &b,const ParticleVertex& a)
+{
+ b.x = a.x - m_systemOffset.x();
+ b.y = a.y - m_systemOffset.y();
+ b.t = a.t;
+ b.lifeSpan = a.lifeSpan;
+ b.size = a.size;
+ b.endSize = a.endSize;
+ b.sx = a.sx;
+ b.sy = a.sy;
+ b.ax = a.ax;
+ b.ay = a.ay;
+}
+
+void DeformableParticle::reload(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ DeformableParticleVertices *particles = (DeformableParticleVertices *) m_node->geometry()->vertexData();
+
+ int pos = particleTypeIndex(d);
+
+ DeformableParticleVertices &p = particles[pos];
+
+ //Perhaps we could be more efficient?
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+ //TODO: Allow for change of deformation data?
+}
+
+void DeformableParticle::load(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ //Deformation Initialization
+ DeformableParticleVertices *particles = (DeformableParticleVertices *) m_node->geometry()->vertexData();
+ DeformableParticleVertices &p = particles[particleTypeIndex(d)];
+ if(m_xVector){
+ const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
+ p.v1.xx = p.v2.xx = p.v3.xx = p.v4.xx = ret.x();
+ p.v1.xy = p.v2.xy = p.v3.xy = p.v4.xy = ret.y();
+ }
+ if(m_yVector){
+ const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
+ p.v1.yx = p.v2.yx = p.v3.yx = p.v4.yx = ret.x();
+ p.v1.yy = p.v2.yy = p.v3.yy = p.v4.yy = ret.y();
+ }
+ p.v1.rotation = p.v2.rotation = p.v3.rotation = p.v4.rotation =
+ (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
+ p.v1.autoRotate = p.v2.autoRotate = p.v3.autoRotate = p.v4.autoRotate = m_autoRotation?1.0:0.0;
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/deformableparticle.h b/src/imports/particles/deformableparticle.h
new file mode 100644
index 0000000000..21982d14da
--- /dev/null
+++ b/src/imports/particles/deformableparticle.h
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEFORMABLEPARTICLE_H
+#define DEFORMABLEPARTICLE_H
+#include "particle.h"
+#include "varyingvector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class DeformableParticleMaterial;
+class QSGGeometryNode;
+struct DeformableParticleVertex;
+
+class DeformableParticle : public ParticleType
+{
+ Q_OBJECT
+ //Note that the particle centering can be less accurate with this one
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
+
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal rotationVariation READ rotationVariation WRITE setRotationVariation NOTIFY rotationVariationChanged)
+ //If true, then will face the direction of motion. Stacks with rotation, e.g. setting rotation
+ //to 180 will lead to facing away from the direction of motion
+ Q_PROPERTY(bool autoRotation READ autoRotation WRITE autoRotation NOTIFY autoRotationChanged)
+
+ //###Ought to be vectors, not points. Varying Vectors even?
+ //###Call i/j? Makes more sense to those with vector calculus experience, and I could even add the cirumflex in QML?
+ //xVector is the vector from the top-left point to the top-right point, and is multiplied by current size
+ Q_PROPERTY(VaryingVector* xVector READ xVector WRITE setXVector NOTIFY xVectorChanged)
+ //yVector is the same, but top-left to bottom-left. The particle is always a parallelogram.
+ Q_PROPERTY(VaryingVector* yVector READ yVector WRITE setYVector NOTIFY yVectorChanged)
+
+ //Do we want to add the tables?
+ //Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
+ //Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
+ //Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
+
+ //Does it need alpha? For convenience only, as images probably don't have it
+ //Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ //Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
+
+public:
+ explicit DeformableParticle(QSGItem *parent = 0);
+ virtual ~DeformableParticle(){}
+
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+
+ QUrl image() const { return m_image; }
+ void setImage(const QUrl &image);
+
+ qreal rotation() const
+ {
+ return m_rotation;
+ }
+
+ bool autoRotation() const
+ {
+ return m_autoRotation;
+ }
+
+ VaryingVector* xVector() const
+ {
+ return m_xVector;
+ }
+
+ VaryingVector* yVector() const
+ {
+ return m_yVector;
+ }
+
+ qreal rotationVariation() const
+ {
+ return m_rotationVariation;
+ }
+
+signals:
+
+ void imageChanged();
+ void rotationChanged(qreal arg);
+
+ void autoRotationChanged(bool arg);
+
+ void xVectorChanged(VaryingVector* arg);
+
+ void yVectorChanged(VaryingVector* arg);
+
+ void rotationVariationChanged(qreal arg);
+
+public slots:
+void setRotation(qreal arg)
+{
+ if (m_rotation != arg) {
+ m_rotation = arg;
+ emit rotationChanged(arg);
+ }
+}
+
+void autoRotation(bool arg)
+{
+ if (m_autoRotation != arg) {
+ m_autoRotation = arg;
+ emit autoRotationChanged(arg);
+ }
+}
+
+void setXVector(VaryingVector* arg)
+{
+ if (m_xVector != arg) {
+ m_xVector = arg;
+ emit xVectorChanged(arg);
+ }
+}
+
+void setYVector(VaryingVector* arg)
+{
+ if (m_yVector != arg) {
+ m_yVector = arg;
+ emit yVectorChanged(arg);
+ }
+}
+
+void setRotationVariation(qreal arg)
+{
+ if (m_rotationVariation != arg) {
+ m_rotationVariation = arg;
+ emit rotationVariationChanged(arg);
+ }
+}
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void reset();
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+private:
+ void vertexCopy(DeformableParticleVertex &b,const ParticleVertex& a);
+ bool m_do_reset;
+
+ QUrl m_image;
+ QSGGeometryNode *m_node;
+ DeformableParticleMaterial *m_material;
+
+ // derived values...
+ int m_last_particle;
+
+ qreal m_render_opacity;
+ // generated vars
+ qreal m_rotation;
+ bool m_autoRotation;
+ VaryingVector* m_xVector;
+ VaryingVector* m_yVector;
+ qreal m_rotationVariation;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // DEFORMABLEPARTICLE_H
diff --git a/src/imports/particles/directedvector.cpp b/src/imports/particles/directedvector.cpp
new file mode 100644
index 0000000000..c1aeba3ad2
--- /dev/null
+++ b/src/imports/particles/directedvector.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directedvector.h"
+#include "particleemitter.h"
+#include <cmath>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+DirectedVector::DirectedVector(QObject *parent) :
+ VaryingVector(parent)
+ , m_targetX(0)
+ , m_targetY(0)
+ , m_targetVariation(0)
+ , m_proportionalMagnitude(false)
+ , m_magnitude(0)
+ , m_magnitudeVariation(0)
+ , m_targetItem(0)
+{
+}
+
+const QPointF &DirectedVector::sample(const QPointF &from)
+{
+ //###This approach loses interpolating the last position of the target (like we could with the emitter) is it worthwhile?
+ qreal targetX;
+ qreal targetY;
+ if(m_targetItem){
+ ParticleEmitter* parentEmitter = qobject_cast<ParticleEmitter*>(parent());
+ targetX = m_targetItem->width()/2;
+ targetY = m_targetItem->height()/2;
+ if(!parentEmitter){
+ qWarning() << "Directed vector is not a child of the emitter. Mapping of target item coordinates may fail.";
+ targetX += m_targetItem->x();
+ targetY += m_targetItem->y();
+ }else{
+ m_ret = parentEmitter->mapFromItem(m_targetItem, QPointF(targetX, targetY));
+ targetX = m_ret.x();
+ targetY = m_ret.y();
+ }
+ }else{
+ targetX = m_targetX;
+ targetY = m_targetY;
+ }
+ targetX += 0 - from.x() - m_targetVariation + rand()/(float)RAND_MAX * m_targetVariation*2;
+ targetY += 0 - from.y() - m_targetVariation + rand()/(float)RAND_MAX * m_targetVariation*2;
+ qreal theta = atan2(targetY, targetX);
+ qreal mag = m_magnitude + rand()/(float)RAND_MAX * m_magnitudeVariation * 2 - m_magnitudeVariation;
+ if(m_proportionalMagnitude)
+ mag *= sqrt(targetX * targetX + targetY * targetY);
+ m_ret.setX(mag * cos(theta));
+ m_ret.setY(mag * sin(theta));
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/directedvector.h b/src/imports/particles/directedvector.h
new file mode 100644
index 0000000000..f1d0919bc3
--- /dev/null
+++ b/src/imports/particles/directedvector.h
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTEDVECTOR_H
+#define DIRECTEDVECTOR_H
+#include "varyingvector.h"
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class DirectedVector : public VaryingVector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal targetX READ targetX WRITE setTargetX NOTIFY targetXChanged)
+ Q_PROPERTY(qreal targetY READ targetY WRITE setTargetY NOTIFY targetYChanged)
+ //If targetItem is set, X/Y are ignored. Aims at middle of item, use variation for variation
+ Q_PROPERTY(QSGItem* targetItem READ targetItem WRITE setTargetItem NOTIFY targetItemChanged)
+
+ Q_PROPERTY(qreal targetVariation READ targetVariation WRITE setTargetVariation NOTIFY targetVariationChanged)
+
+ 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)
+
+public:
+ explicit DirectedVector(QObject *parent = 0);
+ virtual const QPointF &sample(const QPointF &from);
+
+ qreal targetX() const
+ {
+ return m_targetX;
+ }
+
+ qreal targetY() const
+ {
+ return m_targetY;
+ }
+
+ qreal targetVariation() const
+ {
+ return m_targetVariation;
+ }
+
+ qreal magnitude() const
+ {
+ return m_magnitude;
+ }
+
+ bool proportionalMagnitude() const
+ {
+ return m_proportionalMagnitude;
+ }
+
+ qreal magnitudeVariation() const
+ {
+ return m_magnitudeVariation;
+ }
+
+ QSGItem* targetItem() const
+ {
+ return m_targetItem;
+ }
+
+signals:
+
+ void targetXChanged(qreal arg);
+
+ void targetYChanged(qreal arg);
+
+ void targetVariationChanged(qreal arg);
+
+ void magnitudeChanged(qreal arg);
+
+ void proprotionalMagnitudeChanged(bool arg);
+
+ void magnitudeVariationChanged(qreal arg);
+
+ void targetItemChanged(QSGItem* arg);
+
+public slots:
+ void setTargetX(qreal arg)
+ {
+ if (m_targetX != arg) {
+ m_targetX = arg;
+ emit targetXChanged(arg);
+ }
+ }
+
+ void setTargetY(qreal arg)
+ {
+ if (m_targetY != arg) {
+ m_targetY = arg;
+ emit targetYChanged(arg);
+ }
+ }
+
+ void setTargetVariation(qreal arg)
+ {
+ if (m_targetVariation != arg) {
+ m_targetVariation = arg;
+ emit targetVariationChanged(arg);
+ }
+ }
+
+ void setMagnitude(qreal arg)
+ {
+ if (m_magnitude != arg) {
+ m_magnitude = arg;
+ emit magnitudeChanged(arg);
+ }
+ }
+
+ void setProportionalMagnitude(bool arg)
+ {
+ if (m_proportionalMagnitude != arg) {
+ m_proportionalMagnitude = arg;
+ emit proprotionalMagnitudeChanged(arg);
+ }
+ }
+
+ void setMagnitudeVariation(qreal arg)
+ {
+ if (m_magnitudeVariation != arg) {
+ m_magnitudeVariation = arg;
+ emit magnitudeVariationChanged(arg);
+ }
+ }
+
+ void setTargetItem(QSGItem* arg)
+ {
+ if (m_targetItem != arg) {
+ m_targetItem = arg;
+ emit targetItemChanged(arg);
+ }
+ }
+
+private:
+ qreal m_targetX;
+ qreal m_targetY;
+ qreal m_targetVariation;
+ bool m_proportionalMagnitude;
+ qreal m_magnitude;
+ qreal m_magnitudeVariation;
+ QSGItem *m_targetItem;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // DIRECTEDVECTOR_H
diff --git a/src/imports/particles/driftaffector.cpp b/src/imports/particles/driftaffector.cpp
new file mode 100644
index 0000000000..f88e29936a
--- /dev/null
+++ b/src/imports/particles/driftaffector.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "driftaffector.h"
+#include "particlesystem.h"
+QT_BEGIN_NAMESPACE
+DriftAffector::DriftAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+}
+
+DriftAffector::~DriftAffector()
+{
+}
+
+bool DriftAffector::affectParticle(ParticleData *data, qreal dt)
+{
+ if(!m_xDrift && !m_yDrift)
+ return false;
+ qreal dx = (((qreal)qrand() / (qreal)RAND_MAX) - 0.5) * 2 * m_xDrift * dt;
+ qreal dy = (((qreal)qrand() / (qreal)RAND_MAX) - 0.5) * 2 * m_yDrift * dt;
+ if(dx)
+ data->setInstantaneousSX(data->curSX() + dx);
+ if(dy)
+ data->setInstantaneousSY(data->curSY() + dy);
+
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/driftaffector.h b/src/imports/particles/driftaffector.h
new file mode 100644
index 0000000000..91ef0fbd34
--- /dev/null
+++ b/src/imports/particles/driftaffector.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DRIFTAFFECTOR_H
+#define DRIFTAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class DriftAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal xDrift READ xDrift WRITE setXDrift NOTIFY xDriftChanged)
+ Q_PROPERTY(qreal yDrift READ yDrift WRITE setYDrift NOTIFY yDriftChanged)
+public:
+ explicit DriftAffector(QSGItem *parent = 0);
+ ~DriftAffector();
+ qreal yDrift() const
+ {
+ return m_yDrift;
+ }
+
+ qreal xDrift() const
+ {
+ return m_xDrift;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+
+signals:
+
+ void yDriftChanged(qreal arg);
+
+ void xDriftChanged(qreal arg);
+
+public slots:
+
+void setYDrift(qreal arg)
+{
+ if (m_yDrift != arg) {
+ m_yDrift = arg;
+ emit yDriftChanged(arg);
+ }
+}
+
+void setXDrift(qreal arg)
+{
+ if (m_xDrift != arg) {
+ m_xDrift = arg;
+ emit xDriftChanged(arg);
+ }
+}
+
+private:
+ qreal m_yDrift;
+ qreal m_xDrift;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // DRIFTAFFECTOR_H
diff --git a/src/imports/particles/ellipseextruder.cpp b/src/imports/particles/ellipseextruder.cpp
new file mode 100644
index 0000000000..1a0d70594b
--- /dev/null
+++ b/src/imports/particles/ellipseextruder.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ellipseextruder.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+EllipseExtruder::EllipseExtruder(QObject *parent) :
+ ParticleExtruder(parent)
+ , m_fill(true)
+{
+}
+
+QPointF EllipseExtruder::extrude(const QRectF & r)
+{
+ qreal theta = ((qreal)rand()/RAND_MAX) * 6.2831853071795862;
+ qreal mag = m_fill ? ((qreal)rand()/RAND_MAX) : 1;
+ return QPointF(r.x() + r.width()/2 + mag * (r.width()/2) * cos(theta),
+ r.y() + r.height()/2 + mag * (r.height()/2) * sin(theta));
+}
+
+bool EllipseExtruder::contains(const QRectF &bounds, const QPointF &point)
+{
+ return bounds.contains(point);//TODO: Ellipse
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/ellipseextruder.h b/src/imports/particles/ellipseextruder.h
new file mode 100644
index 0000000000..25cc9bc16a
--- /dev/null
+++ b/src/imports/particles/ellipseextruder.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ELLIPSEEXTRUDER_H
+#define ELLIPSEEXTRUDER_H
+#include "particleextruder.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class EllipseExtruder : public ParticleExtruder
+{
+ Q_OBJECT
+ Q_PROPERTY(bool fill READ fill WRITE setFill NOTIFY fillChanged)//###Use base class? If it's still box
+public:
+ explicit EllipseExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ virtual bool contains(const QRectF &bounds, const QPointF &point);
+
+ bool fill() const
+ {
+ return m_fill;
+ }
+
+signals:
+
+ void fillChanged(bool arg);
+
+public slots:
+
+ void setFill(bool arg)
+ {
+ if (m_fill != arg) {
+ m_fill = arg;
+ emit fillChanged(arg);
+ }
+ }
+private:
+ bool m_fill;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ELLIPSEEXTRUDER_H
diff --git a/src/imports/particles/eternalaffector.cpp b/src/imports/particles/eternalaffector.cpp
new file mode 100644
index 0000000000..c946709170
--- /dev/null
+++ b/src/imports/particles/eternalaffector.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "eternalaffector.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+EternalAffector::EternalAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+}
+
+bool EternalAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ qreal target = (m_system->m_timeInt - m_targetLife)/1000.0;
+ if(d->pv.t < target)
+ d->pv.t = target;
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/eternalaffector.h b/src/imports/particles/eternalaffector.h
new file mode 100644
index 0000000000..834106b53d
--- /dev/null
+++ b/src/imports/particles/eternalaffector.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ETERNALAFFECTOR_H
+#define ETERNALAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class EternalAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(int targetLife READ targetLife WRITE setTargetLife NOTIFY targetLifeChanged)
+
+public:
+ explicit EternalAffector(QSGItem *parent = 0);
+ int targetLife() const
+ {
+ return m_targetLife;
+ }
+
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+
+signals:
+
+ void targetLifeChanged(int arg);
+
+public slots:
+
+ void setTargetLife(int arg)
+ {
+ if (m_targetLife != arg) {
+ m_targetLife = arg;
+ emit targetLifeChanged(arg);
+ }
+ }
+private:
+ int m_targetLife;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // ETERNALAFFECTOR_H
diff --git a/src/imports/particles/followemitter.cpp b/src/imports/particles/followemitter.cpp
new file mode 100644
index 0000000000..825b9ea69f
--- /dev/null
+++ b/src/imports/particles/followemitter.cpp
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "followemitter.h"
+#include "particle.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+
+FollowEmitter::FollowEmitter(QSGItem *parent) :
+ ParticleEmitter(parent)
+ , m_lastTimeStamp(0)
+ , m_emitterXVariation(0)
+ , m_emitterYVariation(0)
+ , m_followCount(0)
+ , m_emissionExtruder(0)
+ , m_defaultEmissionExtruder(new ParticleExtruder(this))
+{
+ connect(this, SIGNAL(followChanged(QString)),
+ this, SLOT(recalcParticlesPerSecond()));
+ connect(this, SIGNAL(particleDurationChanged(int)),
+ this, SLOT(recalcParticlesPerSecond()));
+ connect(this, SIGNAL(particlesPerParticlePerSecondChanged(int)),
+ this, SLOT(recalcParticlesPerSecond()));
+}
+
+void FollowEmitter::recalcParticlesPerSecond(){
+ if(!m_system)
+ return;
+ m_followCount = m_system->m_groupData[m_system->m_groupIds[m_follow]]->size;
+ if(!m_followCount){
+ setParticlesPerSecond(1000);//XXX: Fix this horrendous hack, needed so they aren't turned off from start
+ }else{
+ setParticlesPerSecond(m_particlesPerParticlePerSecond * m_followCount);
+ m_lastEmission.resize(m_followCount);
+ m_lastEmission.fill(0);
+ }
+}
+
+void FollowEmitter::reset()
+{
+ m_followCount = 0;
+}
+
+void FollowEmitter::emitWindow(int timeStamp)
+{
+ if (m_system == 0)
+ return;
+ if(!m_emitting && !m_burstLeft && !m_emitLeft)
+ return;
+ if(m_followCount != m_system->m_groupData[m_system->m_groupIds[m_follow]]->size){
+ qreal oldPPS = m_particlesPerSecond;
+ recalcParticlesPerSecond();
+ if(m_particlesPerSecond != oldPPS)
+ return;//system may need to update
+ }
+
+ if(m_burstLeft){
+ m_burstLeft -= timeStamp - m_lastTimeStamp * 1000.;
+ if(m_burstLeft < 0){
+ timeStamp += m_burstLeft;
+ m_burstLeft = 0;
+ }
+ }
+
+ qreal time = timeStamp / 1000.;
+ qreal particleRatio = 1. / m_particlesPerParticlePerSecond;
+ qreal pt;
+
+ //Have to map it into this system, because particlesystem automaps it back
+ QPointF offset = m_system->mapFromItem(this, QPointF(0, 0));
+ qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize;
+
+ int gId = m_system->m_groupIds[m_follow];
+ int gId2 = m_system->m_groupIds[m_particle];
+ for(int i=0; i<m_system->m_groupData[gId]->size; i++){
+ pt = m_lastEmission[i];
+ ParticleData* d = m_system->m_data[i + m_system->m_groupData[gId]->start];
+ if(!d || !d->stillAlive())
+ continue;
+ if(pt < d->pv.t)
+ pt = d->pv.t;
+
+ if(!effectiveExtruder()->contains(QRectF(offset.x(), offset.y(), width(), height()),QPointF(d->curX(), d->curY()))){
+ m_lastEmission[i] = time;//jump over this time period without emitting, because it's outside
+ continue;
+ }
+ while(pt < time || m_emitLeft){
+ ParticleData* datum = m_system->newDatum(gId2);
+ if(!datum){//skip this emission
+ if(m_emitLeft)
+ --m_emitLeft;
+ else
+ pt += particleRatio;
+ continue;
+ }
+ datum->e = this;//###useful?
+ ParticleVertex &p = datum->pv;
+
+ // Particle timestamp
+ p.t = pt;
+ p.lifeSpan =
+ (m_particleDuration
+ + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation))
+ / 1000.0;
+
+ // Particle position
+ qreal followT = pt - d->pv.t;
+ qreal followT2 = followT * followT * 0.5;
+ qreal sizeOffset = d->pv.size/2;//TODO: Current size? As an option
+ //TODO: Set variations
+ //Subtract offset, because PS expects this in emitter coordinates
+ QRectF boundsRect(d->pv.x - offset.x() + d->pv.sx * followT + d->pv.ax * followT2 - m_emitterXVariation/2,
+ d->pv.y - offset.y() + d->pv.sy * followT + d->pv.ay * followT2 - m_emitterYVariation/2,
+ m_emitterXVariation,
+ m_emitterYVariation);
+// QRectF boundsRect(d->pv.x + d->pv.sx * followT + d->pv.ax * followT2 + offset.x() - sizeOffset,
+// d->pv.y + d->pv.sy * followT + d->pv.ay * followT2 + offset.y() - sizeOffset,
+// sizeOffset*2,
+// sizeOffset*2);
+
+ ParticleExtruder* effectiveEmissionExtruder = m_emissionExtruder ? m_emissionExtruder : m_defaultEmissionExtruder;
+ const QPointF &newPos = effectiveEmissionExtruder->extrude(boundsRect);
+ p.x = newPos.x();
+ p.y = newPos.y();
+
+ // Particle speed
+ const QPointF &speed = m_speed->sample(newPos);
+ p.sx = speed.x();
+ p.sy = speed.y();
+
+ // Particle acceleration
+ const QPointF &accel = m_acceleration->sample(newPos);
+ p.ax = accel.x();
+ p.ay = accel.y();
+
+ // Particle size
+ float sizeVariation = -m_particleSizeVariation
+ + rand() / float(RAND_MAX) * m_particleSizeVariation * 2;
+
+ float size = qMax((qreal)0.0, m_particleSize + sizeVariation);
+ float endSize = qMax((qreal)0.0, sizeAtEnd + sizeVariation);
+
+ p.size = size * float(m_emitting);
+ p.endSize = endSize * float(m_emitting);
+
+ if(m_emitLeft)
+ --m_emitLeft;
+ else
+ pt += particleRatio;
+ m_system->emitParticle(datum);
+ }
+ m_lastEmission[i] = pt;
+ }
+
+ m_lastTimeStamp = time;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/followemitter.h b/src/imports/particles/followemitter.h
new file mode 100644
index 0000000000..6df293e2e1
--- /dev/null
+++ b/src/imports/particles/followemitter.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FOLLOWEMITTER_H
+#define FOLLOWEMITTER_H
+#include "particleemitter.h"
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class FollowEmitter : public ParticleEmitter
+{
+ Q_OBJECT
+ Q_PROPERTY(QString follow READ follow WRITE setFollow NOTIFY followChanged)
+ //### Remove, and just document that particles per second is per particle? But has count issues
+ Q_PROPERTY(int particlesPerParticlePerSecond READ particlesPerParticlePerSecond WRITE setParticlesPerParticlePerSecond NOTIFY particlesPerParticlePerSecondChanged)
+
+ //TODO: Document that FollowEmitter's box is where it follows. It emits in a rect centered on the followed particle
+ //TODO: A set of properties that can involve the particle size of the followed
+ Q_PROPERTY(ParticleExtruder* emissionShape READ emissonShape WRITE setEmissionShape NOTIFY emissionShapeChanged)
+ Q_PROPERTY(qreal emissionHeight READ emitterYVariation WRITE setEmitterYVariation NOTIFY emitterYVariationChanged)
+ Q_PROPERTY(qreal emissionWidth READ emitterXVariation WRITE setEmitterXVariation NOTIFY emitterXVariationChanged)
+
+public:
+ explicit FollowEmitter(QSGItem *parent = 0);
+ virtual void emitWindow(int timeStamp);
+ virtual void reset();
+
+ int particlesPerParticlePerSecond() const
+ {
+ return m_particlesPerParticlePerSecond;
+ }
+
+ qreal emitterXVariation() const
+ {
+ return m_emitterXVariation;
+ }
+
+ qreal emitterYVariation() const
+ {
+ return m_emitterYVariation;
+ }
+
+ QString follow() const
+ {
+ return m_follow;
+ }
+
+ ParticleExtruder* emissonShape() const
+ {
+ return m_emissionExtruder;
+ }
+
+signals:
+
+ void particlesPerParticlePerSecondChanged(int arg);
+
+ void emitterXVariationChanged(qreal arg);
+
+ void emitterYVariationChanged(qreal arg);
+
+ void followChanged(QString arg);
+
+ void emissionShapeChanged(ParticleExtruder* arg);
+
+public slots:
+
+ void setParticlesPerParticlePerSecond(int arg)
+ {
+ if (m_particlesPerParticlePerSecond != arg) {
+ m_particlesPerParticlePerSecond = arg;
+ emit particlesPerParticlePerSecondChanged(arg);
+ }
+ }
+ void setEmitterXVariation(qreal arg)
+ {
+ if (m_emitterXVariation != arg) {
+ m_emitterXVariation = arg;
+ emit emitterXVariationChanged(arg);
+ }
+ }
+
+ void setEmitterYVariation(qreal arg)
+ {
+ if (m_emitterYVariation != arg) {
+ m_emitterYVariation = arg;
+ emit emitterYVariationChanged(arg);
+ }
+ }
+
+ void setFollow(QString arg)
+ {
+ if (m_follow != arg) {
+ m_follow = arg;
+ emit followChanged(arg);
+ }
+ }
+
+ void setEmissionShape(ParticleExtruder* arg)
+ {
+ if (m_emissionExtruder != arg) {
+ m_emissionExtruder = arg;
+ emit emissionShapeChanged(arg);
+ }
+ }
+
+private slots:
+ void recalcParticlesPerSecond();
+
+private:
+ QSet<ParticleData*> m_pending;
+ QVector<qreal> m_lastEmission;
+ int m_particlesPerParticlePerSecond;
+ qreal m_lastTimeStamp;
+ qreal m_emitterXVariation;
+ qreal m_emitterYVariation;
+ QString m_follow;
+ int m_followCount;
+ ParticleExtruder* m_emissionExtruder;
+ ParticleExtruder* m_defaultEmissionExtruder;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // FOLLOWEMITTER_H
diff --git a/src/imports/particles/frictionaffector.cpp b/src/imports/particles/frictionaffector.cpp
new file mode 100644
index 0000000000..057bb20958
--- /dev/null
+++ b/src/imports/particles/frictionaffector.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "frictionaffector.h"
+QT_BEGIN_NAMESPACE
+FrictionAffector::FrictionAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_factor(0.0)
+{
+}
+
+bool FrictionAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ if(!m_factor)
+ return false;
+ qreal curSX = d->curSX();
+ qreal curSY = d->curSY();
+ d->setInstantaneousSX(curSX + (curSX * m_factor * -1 * dt));
+ d->setInstantaneousSY(curSY + (curSY * m_factor * -1 * dt));
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/frictionaffector.h b/src/imports/particles/frictionaffector.h
new file mode 100644
index 0000000000..67b5f1029c
--- /dev/null
+++ b/src/imports/particles/frictionaffector.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FRICTIONAFFECTOR_H
+#define FRICTIONAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class FrictionAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal factor READ factor WRITE setFactor NOTIFY factorChanged)
+public:
+ explicit FrictionAffector(QSGItem *parent = 0);
+
+ qreal factor() const
+ {
+ return m_factor;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void factorChanged(qreal arg);
+
+public slots:
+
+void setFactor(qreal arg)
+{
+ if (m_factor != arg) {
+ m_factor = arg;
+ emit factorChanged(arg);
+ }
+}
+
+private:
+qreal m_factor;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // FRICTIONAFFECTOR_H
diff --git a/src/imports/particles/gravitationalsingularityaffector.cpp b/src/imports/particles/gravitationalsingularityaffector.cpp
new file mode 100644
index 0000000000..4dd7d94b7b
--- /dev/null
+++ b/src/imports/particles/gravitationalsingularityaffector.cpp
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gravitationalsingularityaffector.h"
+#include <cmath>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+GravitationalSingularityAffector::GravitationalSingularityAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_strength(0.0), m_x(0), m_y(0)
+{
+}
+
+const qreal LIMIT = 200;
+qreal limit(qreal val){
+ if(qAbs(val) > LIMIT){
+ return val < 0 ? LIMIT * -1 : LIMIT;
+ }else{
+ return val;
+ }
+}
+
+bool GravitationalSingularityAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ if(!m_strength)
+ return false;
+ qreal dx = m_x - d->curX();
+ qreal dy = m_y - d->curY();
+ qreal r = sqrt((dx*dx) + (dy*dy));
+ if(r < 0.1 ){//Simulated event horizion - It's right on top of it, and will never escape again. just stick it here.
+ d->pv.ax = 0;
+ d->pv.ay = 0;
+ d->pv.sx = 0;
+ d->pv.sy = 0;
+ d->pv.x = m_x;
+ d->pv.y = m_y;
+ return true;
+ }else if(r < 50.0){//Too close, typical dt values are far too coarse for simulation. This may kill perf though
+ int parts = floor(100.0/r);
+ ParticleData* f = new ParticleData;//Fake, where it's all in real time for convenience
+ f->pv.x = d->curX();
+ f->pv.y = d->curY();
+ f->pv.sx = limit(d->curSX());
+ f->pv.sy = limit(d->curSY());
+ f->pv.ax = d->pv.ax;
+ f->pv.ay = d->pv.ay;
+ subaffect(f, dt/parts, true);
+ for(int i=1; i<parts; i++)
+ subaffect(f, dt/parts, false);
+
+ //Copy values from f, and turn into 'from start' values
+ qreal t = (m_system->m_timeInt/1000.) - d->pv.t;
+ qreal sy = limit(f->pv.sy) - t*f->pv.ay;
+ qreal y = f->pv.y - t*sy - 0.5 * t*t*f->pv.ay;
+ qreal sx = limit(f->pv.sx) - t*f->pv.ax;
+ qreal x = f->pv.x - t*sx - 0.5 * t*t*f->pv.ax;
+
+ d->pv.ay = f->pv.ay;
+ d->pv.sy = sy;
+ d->pv.y = y;
+ d->pv.ax = f->pv.ax;
+ d->pv.sx = sx;
+ d->pv.x = x;
+ return true;
+ }
+ qreal theta = atan2(dy,dx);
+ qreal ds = (m_strength / (r*r)) * dt;
+ dx = ds * cos(theta);
+ dy = ds * sin(theta);
+ d->setInstantaneousSX(limit(d->pv.sx + dx));
+ d->setInstantaneousSY(limit(d->pv.sy + dy));
+ return true;
+}
+
+const qreal EPSILON = 0.1;
+bool fuzzyCompare(qreal a, qreal b)
+{
+ //Not using qFuzzyCompare because I want control of epsilon
+ return (a >= b - EPSILON && a <= b + EPSILON);
+}
+
+bool fuzzyLess(qreal a, qreal b)
+{
+ //Not using qFuzzyCompare because I want control of epsilon
+ return a <= b + EPSILON;
+}
+
+bool fuzzyMore(qreal a, qreal b)
+{
+ //Not using qFuzzyCompare because I want control of epsilon
+ return a >= b - EPSILON;
+}
+
+bool lineIntersect(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3)
+{
+ if(x3 < qMin(x1,x2) || x3 > qMax(x1,x2) || y3 < qMin(y1,y2) || y3 > qMax(y1,y2))
+ return false;
+ qreal m,c;
+ m = (y2-y1) / (x2-x1);
+ c = y1 - m*x1;
+ return (fuzzyCompare(y3, m*x3 + c));
+}
+
+void GravitationalSingularityAffector::subaffect(ParticleData *d, qreal dt, bool first)
+{
+ if(!first){
+ qreal nextX = d->pv.x + d->pv.sx * dt + d->pv.ax * dt * dt * 0.5;
+ qreal nextY = d->pv.y + d->pv.sy * dt + d->pv.ay * dt * dt * 0.5;
+ if(lineIntersect(d->pv.x, d->pv.y, nextX, nextY, m_x, m_y)){
+ d->pv.ax = 0;
+ d->pv.ay = 0;
+ d->pv.sx = 0;
+ d->pv.sy = 0;
+ d->pv.x = m_x;
+ d->pv.y = m_y;
+ return;
+ //Passed center - the near infinite forces cancel out
+// d->pv.x = m_x + m_x - d->pv.x;
+// d->pv.y = m_y + m_y - d->pv.y;
+// d->pv.sx *= -1;
+// d->pv.sy *= -1;
+// return;
+ }
+ //Simulate advancing a dt
+ d->pv.x = nextX;
+ d->pv.y = nextY;
+ d->pv.sx += d->pv.ax * dt;
+ d->pv.sy += d->pv.ay * dt;
+ }
+ qreal dx = m_x - d->pv.x;
+ qreal dy = m_y - d->pv.y;
+ qreal r = sqrt((dx*dx) + (dy*dy));
+ if(!r)
+ return;
+ qreal theta = atan2(dy,dx);
+ qreal ds = (m_strength / (r*r)) * dt;
+ dx = ds * cos(theta);
+ dy = ds * sin(theta);
+ d->pv.sx = d->pv.sx + dx;
+ d->pv.sy = d->pv.sy + dy;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/gravitationalsingularityaffector.h b/src/imports/particles/gravitationalsingularityaffector.h
new file mode 100644
index 0000000000..7ac5e93e0e
--- /dev/null
+++ b/src/imports/particles/gravitationalsingularityaffector.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GRAVITATIONALSINGULARITYAFFECTOR_H
+#define GRAVITATIONALSINGULARITYAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class GravitationalSingularityAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+public:
+ explicit GravitationalSingularityAffector(QSGItem *parent = 0);
+
+ qreal strength() const
+ {
+ return m_strength;
+ }
+
+ qreal x() const
+ {
+ return m_x;
+ }
+
+ qreal y() const
+ {
+ return m_y;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+ void subaffect(ParticleData *d, qreal dt, bool first);
+signals:
+
+ void strengthChanged(qreal arg);
+
+ void xChanged(qreal arg);
+
+ void yChanged(qreal arg);
+
+public slots:
+
+void setStrength(qreal arg)
+{
+ if (m_strength != arg) {
+ m_strength = arg;
+ emit strengthChanged(arg);
+ }
+}
+
+void setX(qreal arg)
+{
+ if (m_x != arg) {
+ m_x = arg;
+ emit xChanged(arg);
+ }
+}
+
+void setY(qreal arg)
+{
+ if (m_y != arg) {
+ m_y = arg;
+ emit yChanged(arg);
+ }
+}
+
+private:
+qreal m_strength;
+qreal m_x;
+qreal m_y;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // GRAVITATIONALSINGULARITYAFFECTOR_H
diff --git a/src/imports/particles/gravityaffector.cpp b/src/imports/particles/gravityaffector.cpp
new file mode 100644
index 0000000000..02edbacd68
--- /dev/null
+++ b/src/imports/particles/gravityaffector.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gravityaffector.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+const qreal CONV = 0.017453292520444443;
+GravityAffector::GravityAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_acceleration(-10), m_angle(90), m_xAcc(0), m_yAcc(0)
+{
+ connect(this, SIGNAL(accelerationChanged(qreal)),
+ this, SLOT(recalc()));
+ connect(this, SIGNAL(angleChanged(qreal)),
+ this, SLOT(recalc()));
+ recalc();
+}
+
+void GravityAffector::recalc()
+{
+ qreal theta = m_angle * CONV;
+ m_xAcc = m_acceleration * cos(theta);
+ m_yAcc = m_acceleration * sin(theta);
+}
+
+bool GravityAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ bool changed = false;
+ if(d->pv.ax != m_xAcc){
+ d->setInstantaneousAX(m_xAcc);
+ changed = true;
+ }
+ if(d->pv.ay != m_yAcc){
+ d->setInstantaneousAY(m_yAcc);
+ changed = true;
+ }
+ return changed;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/gravityaffector.h b/src/imports/particles/gravityaffector.h
new file mode 100644
index 0000000000..004b59e182
--- /dev/null
+++ b/src/imports/particles/gravityaffector.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GRAVITYAFFECTOR_H
+#define GRAVITYAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class GravityAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged)
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+public:
+ explicit GravityAffector(QSGItem *parent = 0);
+ qreal acceleration() const
+ {
+ return m_acceleration;
+ }
+
+ qreal angle() const
+ {
+ return m_angle;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void accelerationChanged(qreal arg);
+
+ void angleChanged(qreal arg);
+
+public slots:
+void setAcceleration(qreal arg)
+{
+ if (m_acceleration != arg) {
+ m_acceleration = arg;
+ emit accelerationChanged(arg);
+ }
+}
+
+void setAngle(qreal arg)
+{
+ if (m_angle != arg) {
+ m_angle = arg;
+ emit angleChanged(arg);
+ }
+}
+
+private slots:
+ void recalc();
+private:
+ qreal m_acceleration;
+ qreal m_angle;
+
+ qreal m_xAcc;
+ qreal m_yAcc;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // GRAVITYAFFECTOR_H
diff --git a/src/imports/particles/killaffector.cpp b/src/imports/particles/killaffector.cpp
new file mode 100644
index 0000000000..1af77918c5
--- /dev/null
+++ b/src/imports/particles/killaffector.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "killaffector.h"
+#include "particleemitter.h"
+QT_BEGIN_NAMESPACE
+KillAffector::KillAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+}
+
+
+bool KillAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ d->pv.t -= d->pv.lifeSpan;
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/killaffector.h b/src/imports/particles/killaffector.h
new file mode 100644
index 0000000000..937ef321a3
--- /dev/null
+++ b/src/imports/particles/killaffector.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef KILLAFFECTOR_H
+#define KILLAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class KillAffector : public ParticleAffector
+{
+ Q_OBJECT
+public:
+ explicit KillAffector(QSGItem *parent = 0);
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+public slots:
+
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // KILLAFFECTOR_H
diff --git a/src/imports/particles/lineextruder.cpp b/src/imports/particles/lineextruder.cpp
new file mode 100644
index 0000000000..399bdae046
--- /dev/null
+++ b/src/imports/particles/lineextruder.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "lineextruder.h"
+#include <cmath>
+
+LineExtruder::LineExtruder(QObject *parent) :
+ ParticleExtruder(parent), m_mirrored(false)
+{
+}
+
+QPointF LineExtruder::extrude(const QRectF &r)
+{
+ qreal x,y;
+ if(!r.height()){
+ x = r.width() * ((qreal)rand())/RAND_MAX;
+ y = 0;
+ }else{
+ y = r.height() * ((qreal)rand())/RAND_MAX;
+ if(!r.width()){
+ x = 0;
+ }else{
+ x = r.width()/r.height() * y;
+ if(m_mirrored)
+ x = r.width() - x;
+ }
+ }
+ return QPointF(x,y);
+}
diff --git a/src/imports/particles/lineextruder.h b/src/imports/particles/lineextruder.h
new file mode 100644
index 0000000000..925f1b3361
--- /dev/null
+++ b/src/imports/particles/lineextruder.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LINEEXTRUDER_H
+#define LINEEXTRUDER_H
+#include "particleextruder.h"
+
+class LineExtruder : public ParticleExtruder
+{
+ 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)
+
+public:
+ explicit LineExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ bool mirrored() const
+ {
+ return m_mirrored;
+ }
+
+signals:
+
+ void mirroredChanged(bool arg);
+
+public slots:
+
+ void setmirrored(bool arg)
+ {
+ if (m_mirrored != arg) {
+ m_mirrored = arg;
+ emit mirroredChanged(arg);
+ }
+ }
+private:
+ bool m_mirrored;
+};
+
+#endif // LINEEXTRUDER_H
diff --git a/src/imports/particles/main.cpp b/src/imports/particles/main.cpp
new file mode 100644
index 0000000000..b2d5c27306
--- /dev/null
+++ b/src/imports/particles/main.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "V1/qdeclarativeparticles_p.h"
+#include "pluginmain.h"
+#include "spritestate.h"
+#include "spriteengine.h"
+#include "particleaffector.h"
+#include "wanderaffector.h"
+//#include "rockingaffector.h"
+//#include "scalingaffector.h"
+#include "resetaffector.h"
+#include "gravityaffector.h"
+#include "driftaffector.h"
+#include "gravitationalsingularityaffector.h"
+#include "frictionaffector.h"
+#include "meanderaffector.h"
+#include "attractoraffector.h"
+#include "speedlimitaffector.h"
+#include "killaffector.h"
+//#include "zoneaffector.h"
+//#include "toggleaffector.h"
+#include "spritegoalaffector.h"
+#include "swarmaffector.h"
+#include "turbulenceaffector.h"
+#include "eternalaffector.h"
+#include "particlesystem.h"
+#include "particleemitter.h"
+//#include "spriteemitter.h"
+#include "trailsemitter.h"
+#include "particle.h"
+#include "coloredparticle.h"
+#include "spriteparticle.h"
+#include "modelparticle.h"
+//#include "pairedparticle.h"
+#include "spriteimage.h"
+#include "followemitter.h"
+#include "particleextruder.h"
+#include "ellipseextruder.h"
+#include "lineextruder.h"
+#include "maskextruder.h"
+#include "varyingvector.h"
+#include "pointvector.h"
+#include "angledvector.h"
+#include "directedvector.h"
+//#include "followaffector.h"
+#include "deformableparticle.h"
+#include "pictureaffector.h"
+
+QT_BEGIN_NAMESPACE
+
+void ParticlesPlugin::registerTypes(const char *uri)
+{
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.particles"));
+
+ qmlRegisterType<QDeclarativeParticles>(uri, 1, 0, "Particles");
+ qmlRegisterType<QDeclarativeParticleMotion>(uri,1,0,"ParticleMotion");
+ qmlRegisterType<QDeclarativeParticleMotionGravity>(uri,1,0,"ParticleMotionGravity");
+ qmlRegisterType<QDeclarativeParticleMotionLinear>(uri,1,0,"ParticleMotionLinear");
+ qmlRegisterType<QDeclarativeParticleMotionWander>(uri,1,0,"ParticleMotionWander");
+ qmlRegisterType<SpriteState>(uri, 2, 0, "Sprite");
+ qmlRegisterType<SpriteEngine>(uri, 2, 0, "SpriteEngine");
+ qmlRegisterType<SpriteImage>(uri, 2, 0, "SpriteImage");
+
+ qmlRegisterType<ParticleSystem>(uri, 2, 0, "ParticleSystem");
+
+ qmlRegisterType<ParticleType>(uri, 2, 0, "Particle");
+ qmlRegisterType<ColoredParticle>(uri, 2, 0, "ColoredParticle");
+ qmlRegisterType<SpriteParticle>(uri, 2, 0, "SpriteParticle");
+ qmlRegisterType<ModelParticle>(uri, 2, 0, "ModelParticle");
+ //qmlRegisterType<PairedParticle>(uri, 2, 0, "PairedParticle");
+ qmlRegisterType<DeformableParticle>(uri, 2, 0, "DeformableParticle");
+
+ qmlRegisterType<ParticleEmitter>(uri, 2, 0, "ParticleEmitter");
+ qmlRegisterType<TrailsEmitter>(uri, 2, 0, "TrailEmitter");
+
+ qmlRegisterType<FollowEmitter>(uri, 2, 0, "FollowEmitter");
+ qmlRegisterType<ParticleExtruder>(uri, 2, 0, "Box");
+ qmlRegisterType<EllipseExtruder>(uri, 2, 0, "Ellipse");
+ qmlRegisterType<LineExtruder>(uri, 2, 0, "Line");
+ qmlRegisterType<MaskExtruder>(uri, 2, 0, "Mask");
+
+ qmlRegisterType<VaryingVector>(uri, 2, 0, "NullVector");
+ qmlRegisterType<PointVector>(uri, 2, 0, "PointVector");
+ qmlRegisterType<AngledVector>(uri, 2, 0, "AngleVector");
+ qmlRegisterType<DirectedVector>(uri, 2, 0, "DirectedVector");
+
+ qmlRegisterType<ParticleAffector>(uri, 2, 0, "ParticleAffector");
+ qmlRegisterType<WanderAffector>(uri, 2, 0, "Wander");
+ //qmlRegisterType<ScalingAffector>(uri, 2, 0, "Scale");
+ //qmlRegisterType<RockingAffector>(uri, 2, 0, "Rocking");
+ qmlRegisterType<DriftAffector>(uri, 2, 0, "Drift");
+ qmlRegisterType<FrictionAffector>(uri, 2, 0, "Friction");
+ qmlRegisterType<GravitationalSingularityAffector>(uri, 2, 0, "GravitationalSingularity");
+ qmlRegisterType<AttractorAffector>(uri, 2, 0, "Attractor");
+ qmlRegisterType<MeanderAffector>(uri, 2, 0, "Meander");
+ qmlRegisterType<SpeedLimitAffector>(uri, 2, 0, "SpeedLimit");
+ qmlRegisterType<GravityAffector>(uri, 2, 0, "Gravity");
+ qmlRegisterType<EternalAffector>(uri, 2, 0, "Stasis");
+ qmlRegisterType<ResetAffector>(uri, 2, 0, "Reset");
+ //qmlRegisterType<ZoneAffector>(uri, 2, 0, "Zone");
+ //qmlRegisterType<ToggleAffector>(uri, 2, 0, "Toggle");
+ qmlRegisterType<KillAffector>(uri, 2, 0, "Kill");
+ qmlRegisterType<SpriteGoalAffector>(uri, 2, 0, "SpriteGoal");
+ qmlRegisterType<SwarmAffector>(uri, 2, 0 , "Swarm");
+ qmlRegisterType<TurbulenceAffector>(uri, 2, 0 , "Turbulence");
+ qmlRegisterType<PictureAffector>(uri, 2, 0, "Picture");
+}
+
+QT_END_NAMESPACE
+
+Q_EXPORT_PLUGIN2(Particles, QT_PREPEND_NAMESPACE(ParticlesPlugin))
diff --git a/src/imports/particles/maskextruder.cpp b/src/imports/particles/maskextruder.cpp
new file mode 100644
index 0000000000..16c64e0a70
--- /dev/null
+++ b/src/imports/particles/maskextruder.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "maskextruder.h"
+#include <QImage>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+MaskExtruder::MaskExtruder(QObject *parent) :
+ ParticleExtruder(parent)
+ , m_lastWidth(-1)
+ , m_lastHeight(-1)
+{
+}
+
+QPointF MaskExtruder::extrude(const QRectF &r)
+{
+ ensureInitialized(r);
+ if(!m_mask.count())
+ return r.topLeft();
+ const QPointF p = m_mask[rand() % m_mask.count()];
+ //### Should random sub-pixel positioning be added?
+ return p + r.topLeft();
+}
+
+bool MaskExtruder::contains(const QRectF &bounds, const QPointF &point)
+{
+ ensureInitialized(bounds);//###Current usage patterns WILL lead to different bounds/r calls. Separate list?
+ return m_mask.contains(QPointF(point.toPoint() - bounds.topLeft().toPoint()));
+}
+
+void MaskExtruder::ensureInitialized(const QRectF &r)
+{
+ if(m_lastWidth == r.width() && m_lastHeight == r.height())
+ return;
+ m_lastWidth = r.width();
+ m_lastHeight = r.height();
+
+ m_mask.clear();
+ if(m_source.isEmpty())
+ return;
+
+ QImage img(m_source.toLocalFile());
+ img = img.createAlphaMask();
+ img = img.convertToFormat(QImage::Format_Mono);//Else LSB, but I think that's easier
+ img = img.scaled(r.size().toSize());//TODO: Do they need aspect ratio stuff? Or tiling?
+ for(int i=0; i<r.width(); i++){
+ for(int j=0; j<r.height(); j++){
+ if(img.pixelIndex(i,j))//Direct bit manipulation is presumably more efficient
+ m_mask << QPointF(i,j);
+ }
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/maskextruder.h b/src/imports/particles/maskextruder.h
new file mode 100644
index 0000000000..ba63db75d4
--- /dev/null
+++ b/src/imports/particles/maskextruder.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MASKEXTRUDER_H
+#define MASKEXTRUDER_H
+#include "particleextruder.h"
+#include <QUrl>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class MaskExtruder : public ParticleExtruder
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+public:
+ explicit MaskExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ virtual bool contains(const QRectF &bounds, const QPointF &point);
+
+ QUrl source() const
+ {
+ return m_source;
+ }
+
+signals:
+
+ void sourceChanged(QUrl arg);
+
+public slots:
+
+ void setSource(QUrl arg)
+ {
+ if (m_source != arg) {
+ m_source = arg;
+ m_lastHeight = -1;//Trigger reset
+ m_lastWidth = -1;
+ emit sourceChanged(arg);
+ }
+ }
+private:
+ QUrl m_source;
+
+ void ensureInitialized(const QRectF &r);
+ int m_lastWidth;
+ int m_lastHeight;
+ QList<QPointF> m_mask;//TODO: More memory efficient datastructures
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // MASKEXTRUDER_H
diff --git a/src/imports/particles/meanderaffector.cpp b/src/imports/particles/meanderaffector.cpp
new file mode 100644
index 0000000000..8e03cd07fb
--- /dev/null
+++ b/src/imports/particles/meanderaffector.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "meanderaffector.h"
+
+QT_BEGIN_NAMESPACE
+
+MeanderAffector::MeanderAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+}
+
+bool MeanderAffector::affectParticle(ParticleData *data, qreal dt)
+{
+ if(!m_xDrift && !m_yDrift)
+ return false;
+ qreal dx = (((qreal)qrand() / (qreal)RAND_MAX) - 0.5) * 2 * m_xDrift * dt;
+ qreal dy = (((qreal)qrand() / (qreal)RAND_MAX) - 0.5) * 2 * m_yDrift * dt;
+ if(dx)
+ data->setInstantaneousAX(data->pv.ax + dx);
+ if(dy)
+ data->setInstantaneousAY(data->pv.ay + dy);
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/meanderaffector.h b/src/imports/particles/meanderaffector.h
new file mode 100644
index 0000000000..203d20430d
--- /dev/null
+++ b/src/imports/particles/meanderaffector.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MEANDERAFFECTOR_H
+#define MEANDERAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class MeanderAffector : public ParticleAffector
+{
+ Q_OBJECT
+ //Like drift, but affects da/dt instead of ds/dt
+ Q_PROPERTY(qreal xDrift READ xDrift WRITE setXDrift NOTIFY xDriftChanged)
+ Q_PROPERTY(qreal yDrift READ yDrift WRITE setYDrift NOTIFY yDriftChanged)
+public:
+ explicit MeanderAffector(QSGItem *parent = 0);
+
+ qreal xDrift() const
+ {
+ return m_xDrift;
+ }
+
+ qreal yDrift() const
+ {
+ return m_yDrift;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void xDriftChanged(qreal arg);
+
+ void yDriftChanged(qreal arg);
+
+public slots:
+
+ void setXDrift(qreal arg)
+ {
+ if (m_xDrift != arg) {
+ m_xDrift = arg;
+ emit xDriftChanged(arg);
+ }
+ }
+ void setYDrift(qreal arg)
+ {
+ if (m_yDrift != arg) {
+ m_yDrift = arg;
+ emit yDriftChanged(arg);
+ }
+ }
+
+private:
+ qreal m_xDrift;
+ qreal m_yDrift;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // MEANDERAFFECTOR_H
diff --git a/src/imports/particles/modelparticle.cpp b/src/imports/particles/modelparticle.cpp
new file mode 100644
index 0000000000..d1034a4c81
--- /dev/null
+++ b/src/imports/particles/modelparticle.cpp
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "modelparticle.h"
+#include <QtDeclarative/private/qsgvisualitemmodel_p.h>
+#include <qsgnode.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+ModelParticle::ModelParticle(QSGItem *parent) :
+ ParticleType(parent), m_ownModel(false), m_comp(0), m_model(0), m_fade(true)
+{
+ setFlag(QSGItem::ItemHasContents);
+}
+
+QVariant ModelParticle::model() const
+{
+ return m_dataSource;
+}
+
+void ModelParticle::setModel(const QVariant &arg)
+{
+ if(arg == m_dataSource)
+ return;
+ m_dataSource = arg;
+ if(qobject_cast<QSGVisualDataModel*>(arg.value<QObject*>())) {
+ if(m_ownModel && m_model)
+ delete m_model;
+ m_model = qobject_cast<QSGVisualDataModel*>(arg.value<QObject*>());
+ m_ownModel = false;
+ }else{
+ if(!m_model || !m_ownModel)
+ m_model = new QSGVisualDataModel(qmlContext(this));
+ m_model->setModel(m_dataSource);
+ m_ownModel = true;
+ }
+ if(m_comp)
+ m_model->setDelegate(m_comp);
+ emit modelChanged();
+ emit modelCountChanged();
+ connect(m_model, SIGNAL(countChanged()),
+ this, SIGNAL(modelCountChanged()));
+ m_available.clear();
+ for(int i=0; i<m_model->count(); i++)
+ m_available << i;//TODO: Track changes
+}
+
+QDeclarativeComponent *ModelParticle::delegate() const
+{
+ if(m_model)
+ return m_model->delegate();
+ return 0;
+}
+
+void ModelParticle::setDelegate(QDeclarativeComponent *comp)
+{
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(m_model))
+ if (comp == dataModel->delegate())
+ return;
+ m_comp = comp;
+ if(m_model)
+ m_model->setDelegate(comp);
+ emit delegateChanged();
+}
+
+int ModelParticle::modelCount() const
+{
+ if(m_model)
+ return m_model->count();
+ return 0;
+}
+
+
+void ModelParticle::freeze(QSGItem* item)
+{
+ m_stasis << item;
+}
+
+
+void ModelParticle::unfreeze(QSGItem* item)
+{
+ m_stasis.remove(item);
+}
+
+void ModelParticle::take(QSGItem *item, bool prioritize)
+{
+ if(prioritize)
+ m_pendingItems.push_front(item);
+ else
+ m_pendingItems.push_back(item);
+}
+
+void ModelParticle::give(QSGItem *item)
+{
+ //TODO: This
+}
+
+void ModelParticle::load(ParticleData* d)
+{
+ //if(!m_model || !m_model->count())//Not really a 'model' particle anymore
+ // return;
+ int pos = particleTypeIndex(d);
+ if(m_items[pos]){
+ if(m_stasis.contains(m_items[pos]))
+ qWarning() << "Current model particles prefers overwrite:false";
+ //remove old item from the particle that is dying to make room for this one
+ m_items[pos]->setOpacity(0.);
+ if(m_idx[pos] >= 0){
+ m_available << m_idx[pos];
+ m_model->release(m_items[pos]);
+ }else{
+ ModelParticleAttached* mpa;
+ if((mpa = qobject_cast<ModelParticleAttached*>(qmlAttachedPropertiesObject<ModelParticle>(m_items[pos]))))
+ mpa->detach();//reparent as well?
+ }
+ m_idx[pos] = -1;
+ m_items[pos] = 0;
+ m_data[pos] = 0;
+ m_activeCount--;
+ }
+ if(m_available.isEmpty() && m_pendingItems.isEmpty())
+ return;
+ if(m_pendingItems.isEmpty()){
+ m_items[pos] = m_model->item(m_available.first());
+ m_idx[pos] = m_available.first();
+ m_available.pop_front();
+ }else{
+ m_items[pos] = m_pendingItems.front();
+ m_pendingItems.pop_front();
+ m_items[pos]->setX(d->curX() - m_items[pos]->width()/2);
+ m_items[pos]->setY(d->curY() - m_items[pos]->height()/2);
+ ModelParticleAttached* mpa;
+ if((mpa = qobject_cast<ModelParticleAttached*>(qmlAttachedPropertiesObject<ModelParticle>(m_items[pos]))))
+ mpa->attach();
+ m_idx[pos] = -2;
+ }
+ m_items[pos]->setParentItem(this);
+ m_data[pos] = d;
+ m_activeCount++;
+}
+
+void ModelParticle::reload(ParticleData* d)
+{
+ //No-op unless we start copying the data.
+}
+
+void ModelParticle::setCount(int c)
+{
+ ParticleType::setCount(c);//###Do we need our own?
+ m_particleCount = c;
+ reset();
+}
+
+int ModelParticle::count()
+{
+ return m_particleCount;
+}
+
+void ModelParticle::reset()
+{
+ ParticleType::reset();
+ //TODO: Cleanup items?
+ m_items.resize(m_particleCount);
+ m_data.resize(m_particleCount);
+ m_idx.resize(m_particleCount);
+ m_items.fill(0);
+ m_data.fill(0);
+ m_idx.fill(-1);
+ m_available.clear();
+ //m_pendingItems.clear();//TODO: Should this be done? If so, Emit signal?
+ if(m_model)
+ for(int i=0; i<m_model->count(); i++)
+ m_available << i;//TODO: Track changes, then have this in the right place
+}
+
+
+QSGNode* ModelParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d)
+{
+ //Dummy update just to get painting tick
+ if(m_pleaseReset){
+ m_pleaseReset = false;
+ reset();
+ }
+ prepareNextFrame();
+
+ update();//Get called again
+ if(n)
+ n->markDirty(QSGNode::DirtyMaterial);
+ return QSGItem::updatePaintNode(n,d);
+}
+
+void ModelParticle::prepareNextFrame()
+{
+ uint timeStamp = m_system->systemSync(this);
+ qreal curT = timeStamp/1000.0;
+ qreal dt = curT - m_lastT;
+ m_lastT = curT;
+ if(!m_activeCount)
+ return;
+
+ //TODO: Size, better fade?
+ for(int i=0; i<m_particleCount; i++){
+ QSGItem* item = m_items[i];
+ ParticleData* data = m_data[i];
+ if(!item || !data)
+ continue;
+ qreal t = ((timeStamp/1000.0) - data->pv.t) / data->pv.lifeSpan;
+ if(m_stasis.contains(item)) {
+ m_data[i]->pv.t += dt;//Stasis effect
+ continue;
+ }
+ if(t >= 1.0){//Usually happens from load
+ item->setOpacity(0.);
+ if(m_idx[i] >= 0){
+ m_available << m_idx[i];
+ m_model->release(m_items[i]);
+ }else{
+ ModelParticleAttached* mpa;
+ if((mpa = qobject_cast<ModelParticleAttached*>(qmlAttachedPropertiesObject<ModelParticle>(m_items[i]))))
+ mpa->detach();//reparent as well?
+ }
+ m_idx[i] = -1;
+ m_items[i] = 0;
+ m_data[i] = 0;
+ m_activeCount--;
+ }else{//Fade
+ if(m_fade){
+ qreal o = 1.;
+ if(t<0.2)
+ o = t*5;
+ if(t>0.8)
+ o = (1-t)*5;
+ item->setOpacity(o);
+ }else{
+ item->setOpacity(1.);//###Without fade, it's just a binary toggle - if we turn it off we have to turn it back on
+ }
+ }
+ item->setX(data->curX() - item->width()/2);
+ item->setY(data->curY() - item->height()/2);
+ }
+}
+
+ModelParticleAttached *ModelParticle::qmlAttachedProperties(QObject *object)
+{
+ return new ModelParticleAttached(object);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/modelparticle.h b/src/imports/particles/modelparticle.h
new file mode 100644
index 0000000000..4aabd08435
--- /dev/null
+++ b/src/imports/particles/modelparticle.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MODELPARTICLE_H
+#define MODELPARTICLE_H
+#include "particle.h"
+#include <QPointer>
+#include <QSet>
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QSGVisualDataModel;
+class ModelParticleAttached;
+
+class ModelParticle : public ParticleType
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int modelCount READ modelCount NOTIFY modelCountChanged)
+ Q_PROPERTY(bool fade READ fade WRITE setFade NOTIFY fadeChanged)
+ Q_CLASSINFO("DefaultProperty", "delegate")
+public:
+ explicit ModelParticle(QSGItem *parent = 0);
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int modelCount() const;
+
+ bool fade() const { return m_fade; }
+
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+ virtual int count();
+
+ static ModelParticleAttached *qmlAttachedProperties(QObject *object);
+signals:
+ void modelChanged();
+ void delegateChanged();
+ void modelCountChanged();
+ void fadeChanged();
+
+public slots:
+ void freeze(QSGItem* item);
+ void unfreeze(QSGItem* item);
+ void take(QSGItem* item,bool prioritize=false);//take by modelparticle
+ void give(QSGItem* item);//give from modelparticle
+
+ void setFade(bool arg){if(arg == m_fade) return; m_fade = arg; emit fadeChanged();}
+protected:
+ virtual void reset();
+ void prepareNextFrame();
+private:
+ bool m_ownModel;
+ QDeclarativeComponent* m_comp;
+ QSGVisualDataModel *m_model;
+ QVariant m_dataSource;
+ QList<QPointer<QSGItem> > m_deletables;
+ int m_particleCount;
+ bool m_fade;
+
+ QList<QSGItem*> m_pendingItems;
+ QVector<QSGItem*> m_items;
+ QVector<ParticleData*> m_data;
+ QVector<int> m_idx;
+ QList<int> m_available;
+ QSet<QSGItem*> m_stasis;
+ qreal m_lastT;
+ int m_activeCount;
+};
+
+class ModelParticleAttached : public QObject
+{
+ Q_OBJECT
+public:
+ ModelParticleAttached(QObject* parent){;}
+ void detach(){emit detached();}
+ void attach(){emit attached();}
+private:
+Q_SIGNALS:
+ void detached();
+ void attached();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(ModelParticle, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+#endif // MODELPARTICLE_H
diff --git a/src/imports/particles/particle.cpp b/src/imports/particles/particle.cpp
new file mode 100644
index 0000000000..8f4ecbf733
--- /dev/null
+++ b/src/imports/particles/particle.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "particle.h"
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+ParticleType::ParticleType(QSGItem *parent) :
+ QSGItem(parent),
+ m_system(0)
+{
+ connect(this, SIGNAL(xChanged()),
+ this, SLOT(calcSystemOffset()));
+ connect(this, SIGNAL(yChanged()),
+ this, SLOT(calcSystemOffset()));
+}
+
+void ParticleType::componentComplete()
+{
+ if(!m_system)
+ qWarning() << "Particle created without a particle system specified";//TODO: useful QML warnings, like line number?
+ QSGItem::componentComplete();
+}
+
+
+void ParticleType::setSystem(ParticleSystem *arg)
+{
+ if (m_system != arg) {
+ m_system = arg;
+ if(m_system){
+ m_system->registerParticleType(this);
+ connect(m_system, SIGNAL(xChanged()),
+ this, SLOT(calcSystemOffset()));
+ connect(m_system, SIGNAL(yChanged()),
+ this, SLOT(calcSystemOffset()));
+ calcSystemOffset();
+ }
+ emit systemChanged(arg);
+ }
+}
+
+void ParticleType::load(ParticleData*)
+{
+}
+
+void ParticleType::reload(ParticleData*)
+{
+}
+
+void ParticleType::reset()
+{
+ //Have to every time because what it's emitting may have changed and that affects particleTypeIndex
+ m_particleStarts.clear();
+ m_lastStart = 0;
+}
+
+void ParticleType::setCount(int c)
+{
+ if(c == m_count)
+ return;
+ m_count = c;
+ emit countChanged();
+}
+
+int ParticleType::count()
+{
+ return m_count;
+}
+
+
+int ParticleType::particleTypeIndex(ParticleData* d)
+{
+ if(!m_particleStarts.contains(d->group)){
+ m_particleStarts.insert(d->group, m_lastStart);
+ m_lastStart += m_system->m_groupData[d->group]->size;
+ }
+ int ret = m_particleStarts[d->group] + d->particleIndex;
+ Q_ASSERT(ret >=0 && ret < m_count);//XXX: Possibly shouldn't assert, but bugs here were hard to find in the past
+ return ret;
+}
+
+
+void ParticleType::calcSystemOffset()
+{
+ if(!m_system)
+ return;
+ QPointF lastOffset = m_systemOffset;
+ m_systemOffset = this->mapFromItem(m_system, QPointF());
+ if(lastOffset != m_systemOffset){
+ //Reload all particles
+ foreach(const QString &g, m_particles){
+ int gId = m_system->m_groupIds[g];
+ for(int i=0; i<m_system->m_groupData[gId]->size; i++)
+ reload(m_system->m_data[m_system->m_groupData[gId]->start + i]);
+ }
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/particle.h b/src/imports/particles/particle.h
new file mode 100644
index 0000000000..324a7e5d7c
--- /dev/null
+++ b/src/imports/particles/particle.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLE_H
+#define PARTICLE_H
+
+#include <QObject>
+#include <QDebug>
+#include "particlesystem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleType : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(ParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
+ Q_PROPERTY(QStringList particles READ particles WRITE setParticles NOTIFY particlesChanged)
+
+public:
+ explicit ParticleType(QSGItem *parent = 0);
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+ virtual int count();
+ ParticleSystem* system() const
+ {
+ return m_system;
+ }
+
+
+ QStringList particles() const
+ {
+ return m_particles;
+ }
+
+ int particleTypeIndex(ParticleData*);
+ virtual void componentComplete();
+signals:
+ void countChanged();
+ void systemChanged(ParticleSystem* arg);
+
+ void particlesChanged(QStringList arg);
+
+public slots:
+void setSystem(ParticleSystem* arg);
+
+void setParticles(QStringList arg)
+{
+ if (m_particles != arg) {
+ m_particles = arg;
+ emit particlesChanged(arg);
+ }
+}
+private slots:
+ void calcSystemOffset();
+protected:
+ virtual void reset();
+
+// virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *){
+// qDebug() << "Shouldn't be here..." << this;
+// return 0;
+// }
+
+ ParticleSystem* m_system;
+ friend class ParticleSystem;
+ int m_count;
+ bool m_pleaseReset;
+ QStringList m_particles;
+ QHash<int,int> m_particleStarts;
+ int m_lastStart;
+ QPointF m_systemOffset;
+private:
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // PARTICLE_H
diff --git a/src/imports/particles/particleaffector.cpp b/src/imports/particles/particleaffector.cpp
new file mode 100644
index 0000000000..0d7bab577d
--- /dev/null
+++ b/src/imports/particles/particleaffector.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "particleaffector.h"
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+ParticleAffector::ParticleAffector(QSGItem *parent) :
+ QSGItem(parent), m_needsReset(false), m_system(0), m_active(true), m_updateIntSet(false)
+{
+ connect(this, SIGNAL(systemChanged(ParticleSystem*)),
+ this, SLOT(updateOffsets()));
+ connect(this, SIGNAL(xChanged()),
+ this, SLOT(updateOffsets()));
+ connect(this, SIGNAL(yChanged()),
+ this, SLOT(updateOffsets()));//TODO: in componentComplete and all relevant signals
+}
+
+void ParticleAffector::componentComplete()
+{
+ if(!m_system)
+ qWarning() << "Affector created without a particle system specified";//TODO: useful QML warnings, like line number?
+ QSGItem::componentComplete();
+}
+
+void ParticleAffector::affectSystem(qreal dt)
+{
+ if(!m_active)
+ return;
+ if(!m_system){
+ qDebug() << "No system" << this;
+ return;
+ }
+ //If not reimplemented, calls affect particle per particle
+ //But only on particles in targeted system/area
+ if(m_updateIntSet){
+ m_groups.clear();
+ foreach(const QString &p, m_particles)
+ m_groups << m_system->m_groupIds[p];//###Can this occur before group ids are properly assigned?
+ m_updateIntSet = false;
+ }
+ //foreach(ParticleData* d, m_system->m_data){
+ for(int i=0; i<m_system->m_particle_count; i++){
+ ParticleData* d = m_system->m_data[i];
+ if(!d || (m_onceOff && m_onceOffed.contains(d->systemIndex)))
+ continue;
+ if(m_groups.isEmpty() || m_groups.contains(d->group)){
+ if(width() == 0 || height() == 0 || QRectF(m_offset.x(), m_offset.y(), width(), height()).contains(d->curX(), d->curY())){
+ if(affectParticle(d, dt)){
+ m_system->m_needsReset << d;
+ if(m_onceOff)
+ m_onceOffed << d->systemIndex;
+ }
+ }
+ }
+ }
+}
+
+bool ParticleAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ Q_UNUSED(d);
+ Q_UNUSED(dt);
+ return false;
+}
+
+void ParticleAffector::reset(int idx)
+{//TODO: This, among other ones, should be restructured so they don't all need to remember to call the superclass
+ if(m_onceOff)
+ m_onceOffed.remove(idx);
+}
+
+void ParticleAffector::updateOffsets()
+{
+ if(m_system)
+ m_offset = m_system->mapFromItem(this, QPointF(0, 0));
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/particleaffector.h b/src/imports/particles/particleaffector.h
new file mode 100644
index 0000000000..1acb405f3e
--- /dev/null
+++ b/src/imports/particles/particleaffector.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLEAFFECTOR_H
+#define PARTICLEAFFECTOR_H
+
+#include <QObject>
+#include "particlesystem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleAffector : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(ParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
+ Q_PROPERTY(QStringList particles READ particles WRITE setParticles NOTIFY particlesChanged)
+ Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
+ Q_PROPERTY(bool onceOff READ onceOff WRITE setOnceOff NOTIFY onceOffChanged)
+
+public:
+ explicit ParticleAffector(QSGItem *parent = 0);
+ virtual void affectSystem(qreal dt);
+ virtual void reset(int systemIdx);//As some store their own data per idx?
+ ParticleSystem* system() const
+ {
+ return m_system;
+ }
+
+ QStringList particles() const
+ {
+ return m_particles;
+ }
+
+ bool active() const
+ {
+ return m_active;
+ }
+
+ bool onceOff() const
+ {
+ return m_onceOff;
+ }
+
+signals:
+
+ void systemChanged(ParticleSystem* arg);
+
+ void particlesChanged(QStringList arg);
+
+ void activeChanged(bool arg);
+
+ void onceOffChanged(bool arg);
+
+public slots:
+void setSystem(ParticleSystem* arg)
+{
+ if (m_system != arg) {
+ m_system = arg;
+ m_system->registerParticleAffector(this);
+ emit systemChanged(arg);
+ }
+}
+
+void setParticles(QStringList arg)
+{
+ if (m_particles != arg) {
+ m_particles = arg;
+ m_updateIntSet = true;
+ emit particlesChanged(arg);
+ }
+}
+
+void setActive(bool arg)
+{
+ if (m_active != arg) {
+ m_active = arg;
+ emit activeChanged(arg);
+ }
+}
+
+void setOnceOff(bool arg)
+{
+ if (m_onceOff != arg) {
+ m_onceOff = arg;
+ emit onceOffChanged(arg);
+ }
+}
+
+protected:
+ friend class ParticleSystem;
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+ bool m_needsReset;//### What is this really saving?
+ ParticleSystem* m_system;
+ QStringList m_particles;
+ bool activeGroup(int g) {return m_groups.isEmpty() || m_groups.contains(g);}
+ bool m_active;
+ virtual void componentComplete();
+ QPointF m_offset;
+private:
+ QSet<int> m_groups;
+ QSet<int> m_onceOffed;
+ bool m_updateIntSet;
+
+ bool m_onceOff;
+
+private slots:
+ void updateOffsets();
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // PARTICLEAFFECTOR_H
diff --git a/src/imports/particles/particleemitter.cpp b/src/imports/particles/particleemitter.cpp
new file mode 100644
index 0000000000..f490ed643e
--- /dev/null
+++ b/src/imports/particles/particleemitter.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "particleemitter.h"
+QT_BEGIN_NAMESPACE
+ParticleEmitter::ParticleEmitter(QSGItem *parent) :
+ QSGItem(parent)
+ , m_particlesPerSecond(10)
+ , m_particleDuration(1000)
+ , m_particleDurationVariation(0)
+ , m_emitting(true)
+ , m_system(0)
+ , m_extruder(0)
+ , m_defaultExtruder(0)
+ , m_speed(&m_nullVector)
+ , m_acceleration(&m_nullVector)
+ , m_particleSize(16)
+ , m_particleEndSize(-1)
+ , m_particleSizeVariation(0)
+ , m_maxParticleCount(-1)
+ , m_burstLeft(0)
+ , m_emitLeft(0)
+
+{
+ //TODO: Reset speed/acc back to null vector? Or allow null pointer?
+ connect(this, SIGNAL(maxParticleCountChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+ connect(this, SIGNAL(particlesPerSecondChanged(qreal)),
+ this, SIGNAL(particleCountChanged()));
+ connect(this, SIGNAL(particleDurationChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+}
+
+ParticleEmitter::~ParticleEmitter()
+{
+ if(m_defaultExtruder)
+ delete m_defaultExtruder;
+}
+
+void ParticleEmitter::componentComplete()
+{
+ if(!m_system)
+ qWarning() << "Emitter created without a particle system specified";//TODO: useful QML warnings, like line number?
+ QSGItem::componentComplete();
+}
+void ParticleEmitter::emitWindow(int timeStamp)
+{
+ Q_UNUSED(timeStamp);
+}
+
+
+void ParticleEmitter::setEmitting(bool arg)
+{
+ if (m_emitting != arg) {
+ m_emitting = arg;
+ emit emittingChanged(arg);
+ }
+}
+
+
+ParticleExtruder* ParticleEmitter::effectiveExtruder()
+{
+ if(m_extruder)
+ return m_extruder;
+ if(!m_defaultExtruder)
+ m_defaultExtruder = new ParticleExtruder;
+ return m_defaultExtruder;
+}
+
+void ParticleEmitter::pulse(qreal seconds)
+{
+ if(!particleCount())
+ qWarning() << "pulse called on an emitter with a particle count of zero";
+ if(!m_emitting)
+ m_burstLeft = seconds*1000.0;//TODO: Change name to match
+}
+
+void ParticleEmitter::burst(int num)
+{
+ if(!particleCount())
+ qWarning() << "burst called on an emitter with a particle count of zero";
+ m_emitLeft += num;
+}
+
+void ParticleEmitter::setMaxParticleCount(int arg)
+{
+ if (m_maxParticleCount != arg) {
+ if(arg < 0 && m_maxParticleCount >= 0){
+ connect(this, SIGNAL(particlesPerSecondChanged(qreal)),
+ this, SIGNAL(particleCountChanged()));
+ connect(this, SIGNAL(particleDurationChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+ }else if(arg >= 0 && m_maxParticleCount < 0){
+ disconnect(this, SIGNAL(particlesPerSecondChanged(qreal)),
+ this, SIGNAL(particleCountChanged()));
+ disconnect(this, SIGNAL(particleDurationChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+ }
+ m_maxParticleCount = arg;
+ emit maxParticleCountChanged(arg);
+ }
+}
+
+int ParticleEmitter::particleCount() const
+{
+ if(m_maxParticleCount >= 0)
+ return m_maxParticleCount;
+ return m_particlesPerSecond*((m_particleDuration+m_particleDurationVariation)/1000.0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/particleemitter.h b/src/imports/particles/particleemitter.h
new file mode 100644
index 0000000000..61994e52fa
--- /dev/null
+++ b/src/imports/particles/particleemitter.h
@@ -0,0 +1,301 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLEEMITTER_H
+#define PARTICLEEMITTER_H
+
+#include <QSGItem>
+#include <QDebug>
+#include "particlesystem.h"
+#include "particleextruder.h"
+#include "varyingvector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ParticleEmitter : public QSGItem
+{
+ Q_OBJECT
+ //###currently goes in emitters OR sets system. Pick one?
+ Q_PROPERTY(ParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
+ Q_PROPERTY(QString particle READ particle WRITE setParticle NOTIFY particleChanged)
+ Q_PROPERTY(ParticleExtruder* shape READ extruder WRITE setExtruder NOTIFY extruderChanged)
+ Q_PROPERTY(bool emitting READ emitting WRITE setEmitting NOTIFY emittingChanged)
+
+ Q_PROPERTY(qreal particlesPerSecond READ particlesPerSecond WRITE setParticlesPerSecond NOTIFY particlesPerSecondChanged)
+ Q_PROPERTY(int particleDuration READ particleDuration WRITE setParticleDuration NOTIFY particleDurationChanged)
+ Q_PROPERTY(int particleDurationVariation READ particleDurationVariation WRITE setParticleDurationVariation NOTIFY particleDurationVariationChanged)
+ Q_PROPERTY(int maxParticles READ maxParticleCount WRITE setMaxParticleCount NOTIFY maxParticleCountChanged)
+
+ Q_PROPERTY(qreal particleSize READ particleSize WRITE setParticleSize NOTIFY particleSizeChanged)
+ Q_PROPERTY(qreal particleEndSize READ particleEndSize WRITE setParticleEndSize NOTIFY particleEndSizeChanged)
+ Q_PROPERTY(qreal particleSizeVariation READ particleSizeVariation WRITE setParticleSizeVariation NOTIFY particleSizeVariationChanged)
+
+ Q_PROPERTY(VaryingVector *speed READ speed WRITE setSpeed NOTIFY speedChanged)
+ Q_PROPERTY(VaryingVector *acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged)
+public:
+ explicit ParticleEmitter(QSGItem *parent = 0);
+ virtual ~ParticleEmitter();
+ virtual void emitWindow(int timeStamp);
+
+ bool emitting() const
+ {
+ return m_emitting;
+ }
+
+ qreal particlesPerSecond() const
+ {
+ return m_particlesPerSecond;
+ }
+
+ int particleDuration() const
+ {
+ return m_particleDuration;
+ }
+
+ ParticleSystem* system() const
+ {
+ return m_system;
+ }
+
+ QString particle() const
+ {
+ return m_particle;
+ }
+
+ int particleDurationVariation() const
+ {
+ return m_particleDurationVariation;
+ }
+
+ virtual void componentComplete();
+signals:
+ void particlesPerSecondChanged(qreal);
+ void particleDurationChanged(int);
+ void emittingChanged(bool);
+
+ void systemChanged(ParticleSystem* arg);
+
+ void particleChanged(QString arg);
+
+ void particleDurationVariationChanged(int arg);
+
+ void extruderChanged(ParticleExtruder* arg);
+
+ void particleSizeChanged(qreal arg);
+
+ void particleEndSizeChanged(qreal arg);
+
+ void particleSizeVariationChanged(qreal arg);
+
+ void speedChanged(VaryingVector * arg);
+
+ void accelerationChanged(VaryingVector * arg);
+
+ void maxParticleCountChanged(int arg);
+ void particleCountChanged();
+
+public slots:
+ void pulse(qreal seconds);
+ void burst(int num);
+
+ void setEmitting(bool arg);
+
+ void setParticlesPerSecond(qreal arg)
+ {
+ if (m_particlesPerSecond != arg) {
+ m_particlesPerSecond = arg;
+ emit particlesPerSecondChanged(arg);
+ }
+ }
+
+ void setParticleDuration(int arg)
+ {
+ if (m_particleDuration != arg) {
+ m_particleDuration = arg;
+ emit particleDurationChanged(arg);
+ }
+ }
+
+ void setSystem(ParticleSystem* arg)
+ {
+ if (m_system != arg) {
+ m_system = arg;
+ m_system->registerParticleEmitter(this);
+ emit systemChanged(arg);
+ }
+ }
+
+ void setParticle(QString arg)
+ {
+ if (m_particle != arg) {
+ m_particle = arg;
+ emit particleChanged(arg);
+ }
+ }
+
+ void setParticleDurationVariation(int arg)
+ {
+ if (m_particleDurationVariation != arg) {
+ m_particleDurationVariation = arg;
+ emit particleDurationVariationChanged(arg);
+ }
+ }
+ void setExtruder(ParticleExtruder* arg)
+ {
+ if (m_extruder != arg) {
+ m_extruder = arg;
+ emit extruderChanged(arg);
+ }
+ }
+
+ void setParticleSize(qreal arg)
+ {
+ if (m_particleSize != arg) {
+ m_particleSize = arg;
+ emit particleSizeChanged(arg);
+ }
+ }
+
+ void setParticleEndSize(qreal arg)
+ {
+ if (m_particleEndSize != arg) {
+ m_particleEndSize = arg;
+ emit particleEndSizeChanged(arg);
+ }
+ }
+
+ void setParticleSizeVariation(qreal arg)
+ {
+ if (m_particleSizeVariation != arg) {
+ m_particleSizeVariation = arg;
+ emit particleSizeVariationChanged(arg);
+ }
+ }
+
+ void setSpeed(VaryingVector * arg)
+ {
+ if (m_speed != arg) {
+ m_speed = arg;
+ emit speedChanged(arg);
+ }
+ }
+
+ void setAcceleration(VaryingVector * arg)
+ {
+ if (m_acceleration != arg) {
+ m_acceleration = arg;
+ emit accelerationChanged(arg);
+ }
+ }
+
+ void setMaxParticleCount(int arg);
+
+public:
+ int particleCount() const;
+
+ virtual void reset(){;}
+ ParticleExtruder* extruder() const
+ {
+ return m_extruder;
+ }
+
+ qreal particleSize() const
+ {
+ return m_particleSize;
+ }
+
+ qreal particleEndSize() const
+ {
+ return m_particleEndSize;
+ }
+
+ qreal particleSizeVariation() const
+ {
+ return m_particleSizeVariation;
+ }
+
+ VaryingVector * speed() const
+ {
+ return m_speed;
+ }
+
+ VaryingVector * acceleration() const
+ {
+ return m_acceleration;
+ }
+
+ int maxParticleCount() const
+ {
+ return m_maxParticleCount;
+ }
+
+protected:
+ qreal m_particlesPerSecond;
+ int m_particleDuration;
+ int m_particleDurationVariation;
+ bool m_emitting;
+ ParticleSystem* m_system;
+ QString m_particle;
+ ParticleExtruder* m_extruder;
+ ParticleExtruder* m_defaultExtruder;
+ ParticleExtruder* effectiveExtruder();
+ VaryingVector * m_speed;
+ VaryingVector * m_acceleration;
+ qreal m_particleSize;
+ qreal m_particleEndSize;
+ qreal m_particleSizeVariation;
+
+ int m_burstLeft;
+ int m_emitLeft;
+ int m_maxParticleCount;
+private:
+ VaryingVector m_nullVector;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PARTICLEEMITTER_H
diff --git a/src/imports/particles/particleextruder.cpp b/src/imports/particles/particleextruder.cpp
new file mode 100644
index 0000000000..3ff5abf996
--- /dev/null
+++ b/src/imports/particles/particleextruder.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "particleextruder.h"
+
+QT_BEGIN_NAMESPACE
+
+ParticleExtruder::ParticleExtruder(QObject *parent) :
+ QObject(parent), m_fill(true)
+{
+}
+
+QPointF ParticleExtruder::extrude(const QRectF &rect)
+{
+ if(m_fill)
+ return QPointF(((qreal)rand() / RAND_MAX) * rect.width() + rect.x(),
+ ((qreal)rand() / RAND_MAX) * rect.height() + rect.y());
+ int side = rand() % 4;
+ switch(side){//TODO: Doesn't this overlap the corners?
+ case 0:
+ return QPointF(rect.x(),
+ ((qreal)rand() / RAND_MAX) * rect.height() + rect.y());
+ case 1:
+ return QPointF(rect.width() + rect.x(),
+ ((qreal)rand() / RAND_MAX) * rect.height() + rect.y());
+ case 2:
+ return QPointF(((qreal)rand() / RAND_MAX) * rect.width() + rect.x(),
+ rect.y());
+ default:
+ return QPointF(((qreal)rand() / RAND_MAX) * rect.width() + rect.x(),
+ rect.height() + rect.y());
+ }
+}
+
+bool ParticleExtruder::contains(const QRectF &bounds, const QPointF &point)
+{
+ return bounds.contains(point);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/particleextruder.h b/src/imports/particles/particleextruder.h
new file mode 100644
index 0000000000..2c417d3f92
--- /dev/null
+++ b/src/imports/particles/particleextruder.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLEEXTRUDER_H
+#define PARTICLEEXTRUDER_H
+
+#include <QObject>
+#include <QRectF>
+#include <QPointF>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ParticleExtruder : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool fill READ fill WRITE setFill NOTIFY fillChanged)//###Should this be base class, or a BoxExtruder?
+
+public:
+ explicit ParticleExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ virtual bool contains(const QRectF &bounds, const QPointF &point);//###Needed for follow emitter, but does it belong? Only marginally conceptually valid, and that's from user's perspective
+ bool fill() const
+ {
+ return m_fill;
+ }
+
+signals:
+
+ void fillChanged(bool arg);
+
+public slots:
+
+ void setFill(bool arg)
+ {
+ if (m_fill != arg) {
+ m_fill = arg;
+ emit fillChanged(arg);
+ }
+ }
+protected:
+ bool m_fill;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PARTICLEEXTRUDER_H
diff --git a/src/imports/particles/particles.pro b/src/imports/particles/particles.pro
index 90b50e4659..4627956d8c 100644
--- a/src/imports/particles/particles.pro
+++ b/src/imports/particles/particles.pro
@@ -2,14 +2,106 @@ TARGET = qmlparticlesplugin
TARGETPATH = Qt/labs/particles
include(../qimportbase.pri)
-QT += declarative
+HEADERS += \
+ V1/qdeclarativeparticles_p.h \
+ spritestate.h \
+ pluginmain.h \
+ particleaffector.h \
+ wanderaffector.h \
+ #rockingaffector.h \
+ #scalingaffector.h \
+ driftaffector.h \
+ particleemitter.h \
+ particlesystem.h \
+ trailsemitter.h \
+ #spriteemitter.h \
+ particle.h \
+ coloredparticle.h \
+ spriteparticle.h \
+ spritegoalaffector.h \
+ #zoneaffector.h \
+ frictionaffector.h \
+ gravitationalsingularityaffector.h \
+ killaffector.h \
+ speedlimitaffector.h \
+ spriteengine.h \
+ gravityaffector.h \
+ attractoraffector.h \
+ meanderaffector.h \
+ #toggleaffector.h \
+ spriteimage.h \
+ #pairedparticle.h \
+ followemitter.h \
+ swarmaffector.h \
+ turbulenceaffector.h \
+ particleextruder.h \
+ ellipseextruder.h \
+ maskextruder.h \
+ varyingvector.h \
+ pointvector.h \
+ angledvector.h \
+ directedvector.h \
+ modelparticle.h \
+ eternalaffector.h \
+ lineextruder.h \
+ resetaffector.h \
+ deformableparticle.h \
+ pictureaffector.h
SOURCES += \
- qdeclarativeparticles.cpp \
- particles.cpp
+ V1/qdeclarativeparticles.cpp \
+ spritestate.cpp \
+ main.cpp \
+ particleaffector.cpp \
+ wanderaffector.cpp \
+ #rockingaffector.cpp \
+ #scalingaffector.cpp \
+ driftaffector.cpp \
+ particleemitter.cpp \
+ particlesystem.cpp \
+ trailsemitter.cpp \
+ #spriteemitter.cpp \
+ particle.cpp \
+ coloredparticle.cpp \
+ spriteparticle.cpp \
+ spritegoalaffector.cpp \
+ #zoneaffector.cpp \
+ frictionaffector.cpp \
+ gravitationalsingularityaffector.cpp \
+ killaffector.cpp \
+ speedlimitaffector.cpp \
+ spriteengine.cpp \
+ gravityaffector.cpp \
+ attractoraffector.cpp \
+ meanderaffector.cpp \
+ #toggleaffector.cpp \
+ spriteimage.cpp \
+ #pairedparticle.cpp \
+ followemitter.cpp \
+ swarmaffector.cpp \
+ turbulenceaffector.cpp \
+ particleextruder.cpp \
+ ellipseextruder.cpp \
+ maskextruder.cpp \
+ varyingvector.cpp \
+ pointvector.cpp \
+ angledvector.cpp \
+ directedvector.cpp \
+ modelparticle.cpp \
+ eternalaffector.cpp \
+ lineextruder.cpp \
+ resetaffector.cpp \
+ deformableparticle.cpp \
+ pictureaffector.cpp
-HEADERS += \
- qdeclarativeparticles_p.h
+QT += declarative opengl
+
+
+OTHER_FILES += \
+ qmldir
+
+RESOURCES += \
+ spriteparticles.qrc
QTDIR_build:DESTDIR = $$QT_BUILD_TREE/imports/$$TARGETPATH
target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
diff --git a/src/imports/particles/particlesystem.cpp b/src/imports/particles/particlesystem.cpp
new file mode 100644
index 0000000000..1cb7d110ee
--- /dev/null
+++ b/src/imports/particles/particlesystem.cpp
@@ -0,0 +1,392 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "particlesystem.h"
+#include <qsgnode.h>
+#include "particleemitter.h"
+#include "particleaffector.h"
+#include "particle.h"
+#include <cmath>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+ParticleData::ParticleData()
+ : group(0)
+ , e(0)
+ , particleIndex(0)
+ , systemIndex(0)
+{
+ pv.x = 0;
+ pv.y = 0;
+ pv.t = -1;
+ pv.size = 0;
+ pv.endSize = 0;
+ pv.sx = 0;
+ pv.sy = 0;
+ pv.ax = 0;
+ pv.ay = 0;
+}
+
+ParticleSystem::ParticleSystem(QSGItem *parent) :
+ QSGItem(parent), m_particle_count(0), m_running(true) , m_startTime(0), m_overwrite(true)
+{
+ m_groupIds = QHash<QString, int>();
+}
+
+void ParticleSystem::registerParticleType(ParticleType* p)
+{
+ m_particles << QPointer<ParticleType>(p);//###Set or uniqueness checking?
+ reset();
+}
+
+void ParticleSystem::registerParticleEmitter(ParticleEmitter* e)
+{
+ m_emitters << QPointer<ParticleEmitter>(e);//###How to get them out?
+ connect(e, SIGNAL(particleCountChanged()),
+ this, SLOT(countChanged()));
+ connect(e, SIGNAL(particleChanged(QString)),
+ this, SLOT(countChanged()));
+ reset();
+}
+
+void ParticleSystem::registerParticleAffector(ParticleAffector* a)
+{
+ m_affectors << QPointer<ParticleAffector>(a);
+ //reset();//TODO: Slim down the huge batch of resets at the start
+}
+
+void ParticleSystem::countChanged()
+{
+ reset();//Need to give Particles new Count
+}
+
+void ParticleSystem::setRunning(bool arg)
+{
+ if (m_running != arg) {
+ m_running = arg;
+ emit runningChanged(arg);
+ reset();
+ }
+}
+
+void ParticleSystem::componentComplete()
+{
+ QSGItem::componentComplete();
+ reset();
+}
+
+void ParticleSystem::initializeSystem()
+{
+ int oldCount = m_particle_count;
+ m_particle_count = 0;//TODO: Only when changed?
+
+ //### Reset the data too?
+ for(int i=0; i<oldCount; i++){
+ if(m_data[i]){
+ delete m_data[i];
+ m_data[i] = 0;
+ }
+ }
+
+ for(QHash<int, GroupData*>::iterator iter = m_groupData.begin(); iter != m_groupData.end(); iter++)
+ delete (*iter);
+ m_groupData.clear();
+ m_groupIds.clear();
+
+ GroupData* gd = new GroupData;//Default group
+ gd->size = 0;
+ gd->start = -1;
+ gd->nextIdx = 0;
+ m_groupData.insert(0,gd);
+ m_groupIds.insert("",0);
+ m_nextGroupId = 1;
+
+ if(!m_emitters.count() || !m_particles.count())
+ return;
+
+ foreach(ParticleEmitter* e, m_emitters){
+ if(!m_groupIds.contains(e->particle())
+ || (!e->particle().isEmpty() && !m_groupIds[e->particle()])){//or it was accidentally inserted by a failed lookup earlier
+ GroupData* gd = new GroupData;
+ gd->size = 0;
+ gd->start = -1;
+ gd->nextIdx = 0;
+ int id = m_nextGroupId++;
+ m_groupIds.insert(e->particle(), id);
+ m_groupData.insert(id, gd);
+ }
+ m_groupData[m_groupIds[e->particle()]]->size += e->particleCount();
+ }
+
+ for(QHash<int, GroupData*>::iterator iter = m_groupData.begin(); iter != m_groupData.end(); iter++){
+ (*iter)->start = m_particle_count;
+ m_particle_count += (*iter)->size;
+ }
+ m_data.resize(m_particle_count);
+ for(int i=oldCount; i<m_particle_count; i++)
+ m_data[i] = 0;//setup new ones
+
+ if(m_particle_count > 16000)
+ qWarning() << "Particle system contains a vast number of particles (>16000). Expect poor performance";
+
+ foreach(ParticleType* particle, m_particles){
+ int particleCount = 0;
+ if(particle->particles().isEmpty()){//Uses default particle
+ particleCount += m_groupData[0]->size;
+ m_groupData[0]->types << particle;
+ }else{
+ foreach(const QString &group, particle->particles()){
+ particleCount += m_groupData[m_groupIds[group]]->size;
+ m_groupData[m_groupIds[group]]->types << particle;
+ }
+ }
+ particle->setCount(particleCount);
+ particle->m_pleaseReset = true;
+ }
+
+ m_timestamp.start();
+ m_initialized = true;
+ emit systemInitialized();
+}
+
+void ParticleSystem::reset()
+{
+ //Clear guarded pointers which have been deleted
+ int cleared = 0;
+ cleared += m_emitters.removeAll(0);
+ cleared += m_particles.removeAll(0);
+ cleared += m_affectors.removeAll(0);
+ //qDebug() << "Reset" << m_emitters.count() << m_particles.count() << "Cleared" << cleared;
+ foreach(ParticleType* p, m_particles)
+ p->reset();
+ foreach(ParticleEmitter* e, m_emitters)
+ e->reset();
+ if(!m_running)
+ return;
+ initializeSystem();
+ foreach(ParticleType* p, m_particles)
+ p->update();
+}
+
+ParticleData* ParticleSystem::newDatum(int groupId)
+{
+ Q_ASSERT(groupId < m_groupData.count());//XXX shouldn't really be an assert
+ int nextIdx = m_groupData[groupId]->start + m_groupData[groupId]->nextIdx++;
+ if( m_groupData[groupId]->nextIdx >= m_groupData[groupId]->size)
+ m_groupData[groupId]->nextIdx = 0;
+
+ Q_ASSERT(nextIdx < m_data.size());
+ ParticleData* ret;
+ if(m_data[nextIdx]){//Recycle, it's faster.
+ ret = m_data[nextIdx];
+ if(!m_overwrite && ret->stillAlive()){
+ return 0;//Artificial longevity (or too fast emission) means this guy hasn't died. To maintain count, don't emit a new one
+ }//###Reset?
+ }else{
+ ret = new ParticleData;
+ m_data[nextIdx] = ret;
+ }
+
+ ret->system = this;
+ ret->systemIndex = nextIdx;
+ ret->particleIndex = nextIdx - m_groupData[groupId]->start;
+ ret->group = groupId;
+ return ret;
+}
+
+void ParticleSystem::emitParticle(ParticleData* pd)
+{// called from prepareNextFrame()->emitWindow - enforce?
+ //Account for relative emitter position
+ QPointF offset = this->mapFromItem(pd->e, QPointF(0, 0));
+ if(!offset.isNull()){
+ pd->pv.x += offset.x();
+ pd->pv.y += offset.y();
+ }
+
+ foreach(ParticleAffector *a, m_affectors)
+ if(a && a->m_needsReset)
+ a->reset(pd->systemIndex);
+ foreach(ParticleType* p, m_groupData[pd->group]->types)
+ if(p)
+ p->load(pd);
+}
+
+
+
+uint ParticleSystem::systemSync(ParticleType* p)
+{
+ if (!m_running)
+ return 0;
+ if (!m_initialized)
+ return 0;//error in initialization
+
+ if(m_syncList.isEmpty() || m_syncList.contains(p)){//Need to advance the simulation
+ m_syncList.clear();
+
+ //### Elapsed time never shrinks - may cause problems if left emitting for weeks at a time.
+ qreal dt = m_timeInt / 1000.;
+ m_timeInt = m_timestamp.elapsed() + m_startTime;
+ qreal time = m_timeInt / 1000.;
+ dt = time - dt;
+ m_needsReset.clear();
+ foreach(ParticleEmitter* emitter, m_emitters)
+ if(emitter)
+ emitter->emitWindow(m_timeInt);
+ foreach(ParticleAffector* a, m_affectors)
+ if(a)
+ a->affectSystem(dt);
+ foreach(ParticleData* d, m_needsReset)
+ foreach(ParticleType* p, m_groupData[d->group]->types)
+ if(p && d)
+ p->reload(d);
+ }
+ m_syncList << p;
+ return m_timeInt;
+}
+
+//sets the x accleration without affecting the instantaneous x velocity or position
+void ParticleData::setInstantaneousAX(qreal ax)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ qreal sx = (pv.sx + t*pv.ax) - t*ax;
+ qreal ex = pv.x + pv.sx * t + 0.5 * pv.ax * t * t;
+ qreal x = ex - t*sx - 0.5 * t*t*ax;
+
+ pv.ax = ax;
+ pv.sx = sx;
+ pv.x = x;
+}
+
+//sets the x velocity without affecting the instantaneous x postion
+void ParticleData::setInstantaneousSX(qreal vx)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ qreal sx = vx - t*pv.ax;
+ qreal ex = pv.x + pv.sx * t + 0.5 * pv.ax * t * t;
+ qreal x = ex - t*sx - 0.5 * t*t*pv.ax;
+
+ pv.sx = sx;
+ pv.x = x;
+}
+
+//sets the instantaneous x postion
+void ParticleData::setInstantaneousX(qreal x)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ pv.x = x - t*pv.sx - 0.5 * t*t*pv.ax;
+}
+
+//sets the y accleration without affecting the instantaneous y velocity or position
+void ParticleData::setInstantaneousAY(qreal ay)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ qreal sy = (pv.sy + t*pv.ay) - t*ay;
+ qreal ey = pv.y + pv.sy * t + 0.5 * pv.ay * t * t;
+ qreal y = ey - t*sy - 0.5 * t*t*ay;
+
+ pv.ay = ay;
+ pv.sy = sy;
+ pv.y = y;
+}
+
+//sets the y velocity without affecting the instantaneous y position
+void ParticleData::setInstantaneousSY(qreal vy)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ //qDebug() << t << (system->m_timeInt/1000.0) << pv.x << pv.sx << pv.ax << pv.x + pv.sx * t + 0.5 * pv.ax * t * t;
+ qreal sy = vy - t*pv.ay;
+ qreal ey = pv.y + pv.sy * t + 0.5 * pv.ay * t * t;
+ qreal y = ey - t*sy - 0.5 * t*t*pv.ay;
+
+ pv.sy = sy;
+ pv.y = y;
+}
+
+//sets the instantaneous Y position
+void ParticleData::setInstantaneousY(qreal y)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ pv.y = y - t*pv.sy - 0.5 * t*t*pv.ay;
+}
+
+qreal ParticleData::curX() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ return pv.x + pv.sx * t + 0.5 * pv.ax * t * t;
+}
+
+qreal ParticleData::curSX() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ return pv.sx + t*pv.ax;
+}
+
+qreal ParticleData::curY() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ return pv.y + pv.sy * t + 0.5 * pv.ay * t * t;
+}
+
+qreal ParticleData::curSY() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ return pv.sy + t*pv.ay;
+}
+
+void ParticleData::debugDump()
+{
+ qDebug() << "Particle" << group
+ << "Pos: " << pv.x << "," << pv.y
+ << "Vel: " << pv.sx << "," << pv.sy
+ << "Acc: " << pv.ax << "," << pv.ay
+ << "Size: " << pv.size << "," << pv.endSize
+ << "Time: " << pv.t << "," <<pv.lifeSpan;
+}
+
+bool ParticleData::stillAlive()
+{
+ if(!system)
+ return false;
+ return (pv.t + pv.lifeSpan) > (system->m_timeInt/1000.0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/particlesystem.h b/src/imports/particles/particlesystem.h
new file mode 100644
index 0000000000..36ac8ed81d
--- /dev/null
+++ b/src/imports/particles/particlesystem.h
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLESYSTEM_H
+#define PARTICLESYSTEM_H
+
+#include <QSGItem>
+#include <QTime>
+#include <QVector>
+#include <QHash>
+#include <QPointer>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleAffector;
+class ParticleEmitter;
+class ParticleType;
+class ParticleData;
+
+
+struct GroupData{
+ int size;
+ int start;
+ int nextIdx;
+ QList<ParticleType*> types;
+};
+
+class ParticleSystem : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+ Q_PROPERTY(int startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
+ Q_PROPERTY(bool overwrite READ overwrite WRITE setOverwrite NOTIFY overwriteChanged)//XXX: Should just be an implementation detail, but I can't decide which way
+
+public:
+ explicit ParticleSystem(QSGItem *parent = 0);
+
+bool isRunning() const
+{
+ return m_running;
+}
+
+int startTime() const
+{
+ return m_startTime;
+}
+
+int count(){ return m_particle_count; }
+
+signals:
+
+void systemInitialized();
+void runningChanged(bool arg);
+
+void startTimeChanged(int arg);
+
+
+void overwriteChanged(bool arg);
+
+public slots:
+void reset();
+void setRunning(bool arg);
+
+
+void setStartTime(int arg)
+{
+ m_startTime = arg;
+}
+
+void setOverwrite(bool arg)
+{
+ if (m_overwrite != arg) {
+ m_overwrite = arg;
+emit overwriteChanged(arg);
+}
+}
+
+protected:
+ void componentComplete();
+
+private slots:
+ void countChanged();
+public://but only really for related class usage. Perhaps we should all be friends?
+ void emitParticle(ParticleData* p);
+ ParticleData* newDatum(int groupId);
+ uint systemSync(ParticleType* p);
+ QTime m_timestamp;
+ QVector<ParticleData*> m_data;
+ QSet<ParticleData*> m_needsReset;
+ QHash<QString, int> m_groupIds;
+ QHash<int, GroupData*> m_groupData;//id, size, start
+ uint m_timeInt;
+ bool m_initialized;
+
+ void registerParticleType(ParticleType* p);
+ void registerParticleEmitter(ParticleEmitter* e);
+ void registerParticleAffector(ParticleAffector* a);
+ bool overwrite() const
+ {
+ return m_overwrite;
+ }
+
+ int m_particle_count;
+private:
+ void initializeSystem();
+ bool m_running;
+ QList<QPointer<ParticleEmitter> > m_emitters;
+ QList<QPointer<ParticleAffector> > m_affectors;
+ QList<QPointer<ParticleType> > m_particles;
+ QList<QPointer<ParticleType> > m_syncList;
+ int m_startTime;
+ int m_nextGroupId;
+ bool m_overwrite;
+};
+
+//TODO: Clean up all this into ParticleData
+
+struct ParticleVertex {
+ float x;
+ float y;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ //TODO: Need opacity over life control. More variable size over life?
+};
+
+class ParticleData{
+public:
+ ParticleData();
+
+ ParticleVertex pv;
+
+ //Convenience functions for working backwards, because parameters are from the start of particle life
+ //If setting multiple parameters at once, doing the conversion yourself will be faster.
+
+ //sets the x accleration without affecting the instantaneous x velocity or position
+ void setInstantaneousAX(qreal ax);
+ //sets the x velocity without affecting the instantaneous x postion
+ void setInstantaneousSX(qreal vx);
+ //sets the instantaneous x postion
+ void setInstantaneousX(qreal x);
+ //sets the y accleration without affecting the instantaneous y velocity or position
+ void setInstantaneousAY(qreal ay);
+ //sets the y velocity without affecting the instantaneous y postion
+ void setInstantaneousSY(qreal vy);
+ //sets the instantaneous Y postion
+ void setInstantaneousY(qreal y);
+
+ //TODO: Slight caching?
+ qreal curX() const;
+ qreal curSX() const;
+ qreal curY() const;
+ qreal curSY() const;
+
+ int group;
+ ParticleEmitter* e;
+ ParticleSystem* system;
+ int particleIndex;
+ int systemIndex;
+
+ void debugDump();
+ bool stillAlive();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PARTICLESYSTEM_H
+
+
diff --git a/src/imports/particles/pictureaffector.cpp b/src/imports/particles/pictureaffector.cpp
new file mode 100644
index 0000000000..c05a553f39
--- /dev/null
+++ b/src/imports/particles/pictureaffector.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pictureaffector.h"
+#include "coloredparticle.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+PictureAffector::PictureAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+ m_needsReset = true;
+}
+
+void PictureAffector::reset(int systemIdx)
+{
+ ParticleAffector::reset(systemIdx);
+}
+
+bool PictureAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ if(!width() || !height()){
+ qWarning() << "PictureAffector needs a size";
+ return false;
+ }
+
+ if(m_loadedImage.isNull())
+ return false;
+
+ if(m_loadedImage.size()!=QSize(width(), height()))
+ m_loadedImage = m_loadedImage.scaled(width(), height());//TODO: Aspect Ratio Control?
+
+ bool affected = false;
+ QPoint pos = QPoint(d->curX() - m_offset.x(), d->curY() - m_offset.y());
+ if(!QRect(0,0,width(),height()).contains(pos)){
+ //XXX: Just a debugging helper, as I don't think it can get here.
+ qWarning() << "An unexpected situation has occurred. But don't worry, everything will be fine.";
+ return false;
+ }
+ Color4ub c;
+ QRgb col = m_loadedImage.pixel(pos);
+ c.a = qAlpha(col);
+ c.b = qBlue(col);
+ c.g = qGreen(col);
+ c.r = qRed(col);
+ foreach(ParticleType *p, m_system->m_groupData[d->group]->types){
+ if(qobject_cast<ColoredParticle*>(p)){
+ ColoredParticle* cp = qobject_cast<ColoredParticle*>(p);
+ cp->reloadColor(c, d);
+ affected = true;
+ }
+ }
+
+ return affected;//Doesn't affect particle data, but necessary for onceOff
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/pictureaffector.h b/src/imports/particles/pictureaffector.h
new file mode 100644
index 0000000000..ca7d13f477
--- /dev/null
+++ b/src/imports/particles/pictureaffector.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PICTUREAFFECTOR_H
+#define PICTUREAFFECTOR_H
+#include "particleaffector.h"
+#include <QDebug>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class PictureAffector : public ParticleAffector
+{
+ Q_OBJECT
+ //Usually want to use "particles" to target just colored stuff, and save performance
+ //Use onceOff (inherited) to determine if this is an emitter modification or a more constant enforcer
+ //TODO: Onceoff isn't actually working right now...
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
+ //TODO: Bool smooth, where it interpolates
+public:
+ explicit PictureAffector(QSGItem *parent = 0);
+
+ QUrl image() const
+ {
+ return m_image;
+ }
+
+protected:
+ virtual void reset(int systemIdx);
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void imageChanged(QUrl arg);
+
+public slots:
+ void setImage(QUrl arg)
+ {
+ if (m_image != arg) {
+ m_image = arg;
+ m_loadedImage = QImage(m_image.toLocalFile());
+ if(m_loadedImage.isNull())
+ qWarning() << "PictureAffector could not load picture " << m_image.toLocalFile();
+ emit imageChanged(arg);
+ }
+ }
+
+private:
+ QUrl m_image;
+ QImage m_loadedImage;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PICTUREAFFECTOR_H
diff --git a/src/imports/particles/pluginmain.h b/src/imports/particles/pluginmain.h
new file mode 100644
index 0000000000..cd8760d1a0
--- /dev/null
+++ b/src/imports/particles/pluginmain.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PLUGINMAIN_H
+#define PLUGINMAIN_H
+
+#include <QtDeclarative>
+#include <QtDeclarative/QDeclarativeExtensionPlugin>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ParticlesPlugin : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+public:
+ virtual void registerTypes(const char *uri);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PLUGINMAIN_H
diff --git a/src/imports/particles/pointvector.cpp b/src/imports/particles/pointvector.cpp
new file mode 100644
index 0000000000..e222965943
--- /dev/null
+++ b/src/imports/particles/pointvector.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pointvector.h"
+
+QT_BEGIN_NAMESPACE
+
+PointVector::PointVector(QObject *parent) :
+ VaryingVector(parent)
+ , m_x(0)
+ , m_y(0)
+ , m_xVariation(0)
+ , m_yVariation(0)
+{
+}
+
+const QPointF &PointVector::sample(const QPointF &)
+{
+ m_ret.setX(m_x - m_xVariation + rand() / float(RAND_MAX) * m_xVariation * 2);
+ m_ret.setY(m_y - m_yVariation + rand() / float(RAND_MAX) * m_yVariation * 2);
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/pointvector.h b/src/imports/particles/pointvector.h
new file mode 100644
index 0000000000..5ffa896680
--- /dev/null
+++ b/src/imports/particles/pointvector.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef POINTVECTOR_H
+#define POINTVECTOR_H
+#include "varyingvector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class PointVector : public VaryingVector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ 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)
+public:
+ explicit PointVector(QObject *parent = 0);
+ virtual const QPointF &sample(const QPointF &from);
+ qreal x() const
+ {
+ return m_x;
+ }
+
+ qreal y() const
+ {
+ return m_y;
+ }
+
+ qreal xVariation() const
+ {
+ return m_xVariation;
+ }
+
+ qreal yVariation() const
+ {
+ return m_yVariation;
+ }
+
+signals:
+
+ void xChanged(qreal arg);
+
+ void yChanged(qreal arg);
+
+ void xVariationChanged(qreal arg);
+
+ void yVariationChanged(qreal arg);
+
+public slots:
+ void setX(qreal arg)
+ {
+ if (m_x != arg) {
+ m_x = arg;
+ emit xChanged(arg);
+ }
+ }
+
+ void setY(qreal arg)
+ {
+ if (m_y != arg) {
+ m_y = arg;
+ emit yChanged(arg);
+ }
+ }
+
+ void setXVariation(qreal arg)
+ {
+ if (m_xVariation != arg) {
+ m_xVariation = arg;
+ emit xVariationChanged(arg);
+ }
+ }
+
+ void setYVariation(qreal arg)
+ {
+ if (m_yVariation != arg) {
+ m_yVariation = arg;
+ emit yVariationChanged(arg);
+ }
+ }
+
+private:
+
+ qreal m_x;
+ qreal m_y;
+ qreal m_xVariation;
+ qreal m_yVariation;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // POINTVECTOR_H
diff --git a/src/imports/particles/resetaffector.cpp b/src/imports/particles/resetaffector.cpp
new file mode 100644
index 0000000000..0598298f27
--- /dev/null
+++ b/src/imports/particles/resetaffector.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "resetaffector.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+ResetAffector::ResetAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+}
+
+void ResetAffector::reset(int idx)
+{
+ ParticleAffector::reset(idx);
+ if(m_data[idx])
+ delete m_data[idx];
+ m_data.insert(idx, 0);//TODO: Either load with data now, or get data next tick whether active or not
+}
+
+bool ResetAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ TrajectoryData* trajectory;
+ if(m_data[d->systemIndex]){
+ trajectory = m_data[d->systemIndex];
+ //TODO: Faster to calculate once (not 4 times)
+ d->setInstantaneousSX(trajectory->sx);
+ d->setInstantaneousSY(trajectory->sy);
+ d->setInstantaneousAX(trajectory->ax);
+ d->setInstantaneousAY(trajectory->ay);
+ }else{
+ trajectory = new TrajectoryData;
+ }
+ trajectory->sx = d->pv.sx;
+ trajectory->sy = d->pv.sy;
+ trajectory->ax = d->pv.ax;
+ trajectory->ay = d->pv.ay;
+ m_data.insert(d->systemIndex, trajectory);//overwrites
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/resetaffector.h b/src/imports/particles/resetaffector.h
new file mode 100644
index 0000000000..6a4e2b7983
--- /dev/null
+++ b/src/imports/particles/resetaffector.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RESETAFFECTOR_H
+#define RESETAFFECTOR_H
+#include "particleaffector.h"
+#include <QHash>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+struct TrajectoryData{
+ qreal sx,sy,ax,ay;
+};
+
+class ResetAffector : public ParticleAffector
+{
+ Q_OBJECT
+public:
+ explicit ResetAffector(QSGItem *parent = 0);
+ virtual void reset(int systemIdx);
+
+signals:
+
+public slots:
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+private:
+ QHash<int, TrajectoryData*> m_data;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // RESETAFFECTOR_H
diff --git a/src/imports/particles/resources/ctfragment.shader b/src/imports/particles/resources/ctfragment.shader
new file mode 100644
index 0000000000..a17f5841ca
--- /dev/null
+++ b/src/imports/particles/resources/ctfragment.shader
@@ -0,0 +1,11 @@
+uniform sampler2D texture;
+uniform sampler2D colortable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex).w) * fColor * texture2D(colortable, vec2(tt, 0.5)) *( texture2D(opacitytable, vec2(tt, 0.5)).w);
+}
diff --git a/src/imports/particles/resources/ctvertex.shader b/src/imports/particles/resources/ctvertex.shader
new file mode 100644
index 0000000000..b20676cc49
--- /dev/null
+++ b/src/imports/particles/resources/ctvertex.shader
@@ -0,0 +1,38 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute lowp vec4 vColor;
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform sampler2D sizetable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ fTex = vTex;
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ highp float currentSize = mix(size, endSize, t * t) * texture2D(sizetable, vec2(t,0.5)).w;
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos = vPos
+ - currentSize / 2. + currentSize * vTex // adjust size
+ + vVec.xy * t * vData.y // apply speed vector..
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ fColor = vColor;
+ tt = t;
+
+}
diff --git a/src/imports/particles/resources/defaultFadeInOut.png b/src/imports/particles/resources/defaultFadeInOut.png
new file mode 100644
index 0000000000..89c04eaefe
--- /dev/null
+++ b/src/imports/particles/resources/defaultFadeInOut.png
Binary files differ
diff --git a/src/imports/particles/resources/deformablefragment.shader b/src/imports/particles/resources/deformablefragment.shader
new file mode 100644
index 0000000000..494053e319
--- /dev/null
+++ b/src/imports/particles/resources/deformablefragment.shader
@@ -0,0 +1,8 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex)) * fFade;
+}
diff --git a/src/imports/particles/resources/deformablevertex.shader b/src/imports/particles/resources/deformablevertex.shader
new file mode 100644
index 0000000000..1ea7f22046
--- /dev/null
+++ b/src/imports/particles/resources/deformablevertex.shader
@@ -0,0 +1,57 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
+attribute highp vec2 vRotation; //x = radians of rotation, y= bool autoRotate
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+void main() {
+ fTex = vTex;
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ highp float currentSize = mix(size, endSize, t * t);
+
+ highp vec2 pos;
+ if (t < 0. || t > 1.){
+ currentSize = 0.;
+ pos = vPos;
+ }else{
+ highp float rotation = vRotation.x;
+ if(vRotation.y == 1.0){
+ highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ rotation += atan(curVel.y, curVel.x);
+ }
+ highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ highp vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ highp vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ pos = vPos
+ + xRotatedDeform
+ + yRotatedDeform
+ //- vec2(1,1) * currentSize * 0.5 // 'center'
+ + vVec.xy * t * vData.y // apply speed
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+ }
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ fFade = fadeIn * fadeOut * opacity;
+}
diff --git a/src/imports/particles/resources/identitytable.png b/src/imports/particles/resources/identitytable.png
new file mode 100644
index 0000000000..2cada1bfad
--- /dev/null
+++ b/src/imports/particles/resources/identitytable.png
Binary files differ
diff --git a/src/imports/particles/resources/spritefragment.shader b/src/imports/particles/resources/spritefragment.shader
new file mode 100644
index 0000000000..4d89d69c6a
--- /dev/null
+++ b/src/imports/particles/resources/spritefragment.shader
@@ -0,0 +1,10 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+
+void main() {
+ gl_FragColor = mix(texture2D(texture, fTexA), texture2D(texture, fTexB), progress) * fColor.w;
+}
diff --git a/src/imports/particles/resources/spriteimagefragment.shader b/src/imports/particles/resources/spriteimagefragment.shader
new file mode 100644
index 0000000000..ecd62cf390
--- /dev/null
+++ b/src/imports/particles/resources/spriteimagefragment.shader
@@ -0,0 +1,9 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+
+void main() {
+ gl_FragColor = mix(texture2D(texture, fTexA), texture2D(texture, fTexB), progress);
+}
diff --git a/src/imports/particles/resources/spriteimagevertex.shader b/src/imports/particles/resources/spriteimagevertex.shader
new file mode 100644
index 0000000000..27de2ada6a
--- /dev/null
+++ b/src/imports/particles/resources/spriteimagevertex.shader
@@ -0,0 +1,52 @@
+attribute highp vec2 vTex;
+attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+uniform highp float framecount; //maximum of all anims
+uniform highp float animcount;
+uniform highp float width;
+uniform highp float height;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+
+
+void main() {
+ //Calculate frame location in texture
+ highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);
+ progress = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;
+
+ frameIndex = floor(frameIndex);
+ highp vec2 frameTex;
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+
+ fTexA = frameTex;
+ //Next frame is also passed, for interpolation
+ if(frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop
+ frameIndex = mod(frameIndex+1., vAnimData.z);
+
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+ fTexB = frameTex;
+
+
+ gl_Position = matrix * vec4(width * vTex.x, height * vTex.y, 0, 1);
+}
diff --git a/src/imports/particles/resources/spritevertex.shader b/src/imports/particles/resources/spritevertex.shader
new file mode 100644
index 0000000000..78b8e36b3b
--- /dev/null
+++ b/src/imports/particles/resources/spritevertex.shader
@@ -0,0 +1,77 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+uniform highp float framecount; //maximum of all anims
+uniform highp float animcount;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+
+void main() {
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ //Calculate frame location in texture
+ highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);
+ progress = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;
+
+ frameIndex = floor(frameIndex);
+ highp vec2 frameTex = vTex;
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+
+ fTexA = frameTex;
+ //Next frame is also passed, for interpolation
+ //### Should the next anim be precalculated to allow for interpolation there?
+ if(frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop
+ frameIndex = mod(frameIndex+1., vAnimData.z);
+
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+ fTexB = frameTex;
+
+ //Applying Size here seems to screw with RockingAffector?
+ highp float currentSize = mix(size, endSize, t * t);
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ //If affector is mananging pos, they don't set speed?
+ highp vec2 pos = vPos
+ - currentSize / 2. + currentSize * vTex // adjust size
+ + vVec.xy * t * vData.y // apply speed vector..
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ // calculate opacity
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ lowp vec4 white = vec4(1.);
+ fColor = white * fadeIn * fadeOut * opacity;
+}
diff --git a/src/imports/particles/resources/trailsfragment.shader b/src/imports/particles/resources/trailsfragment.shader
new file mode 100644
index 0000000000..d3db87fa30
--- /dev/null
+++ b/src/imports/particles/resources/trailsfragment.shader
@@ -0,0 +1,8 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex).w) * fColor;
+}
diff --git a/src/imports/particles/resources/trailsvertex.shader b/src/imports/particles/resources/trailsvertex.shader
new file mode 100644
index 0000000000..7bc1d66b71
--- /dev/null
+++ b/src/imports/particles/resources/trailsvertex.shader
@@ -0,0 +1,37 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute lowp vec4 vColor;
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+
+void main() {
+ fTex = vTex;
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ highp float currentSize = mix(size, endSize, t * t);
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos = vPos
+ - currentSize / 2. + currentSize * vTex // adjust size
+ + vVec.xy * t * vData.y // apply speed vector..
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ fColor = vColor * fadeIn * fadeOut * opacity;
+}
diff --git a/src/imports/particles/speedlimitaffector.cpp b/src/imports/particles/speedlimitaffector.cpp
new file mode 100644
index 0000000000..c226404b01
--- /dev/null
+++ b/src/imports/particles/speedlimitaffector.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "speedlimitaffector.h"
+#include <cmath>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+SpeedLimitAffector::SpeedLimitAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_speedLimit(-1)
+{
+}
+
+bool SpeedLimitAffector::affectParticle(ParticleData *d, qreal dt){
+ Q_UNUSED(dt);
+ if(m_speedLimit <= 0)
+ return false;
+
+ qreal x = d->curSX();
+ qreal y = d->curSY();
+ qreal s = sqrt(x*x + y*y);
+ if(s <= m_speedLimit)
+ return false;
+
+
+ if(s >= m_speedLimit*1.01){
+ qreal theta = atan2(y,x);
+ d->setInstantaneousSX(m_speedLimit * cos(theta));
+ d->setInstantaneousSY(m_speedLimit * sin(theta));
+ }
+
+ d->setInstantaneousAY(0);
+ d->setInstantaneousAX(0);
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/speedlimitaffector.h b/src/imports/particles/speedlimitaffector.h
new file mode 100644
index 0000000000..b3858a2a9d
--- /dev/null
+++ b/src/imports/particles/speedlimitaffector.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPEEDLIMITAFFECTOR_H
+#define SPEEDLIMITAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class SpeedLimitAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal speedLimit READ speedLimit WRITE setSpeedLimit NOTIFY speedLimitChanged)
+
+
+public:
+ explicit SpeedLimitAffector(QSGItem *parent = 0);
+
+ qreal speedLimit() const
+ {
+ return m_speedLimit;
+ }
+
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void speedLimitChanged(qreal arg);
+
+public slots:
+void setSpeedLimit(qreal arg)
+{
+ if (m_speedLimit != arg) {
+ m_speedLimit = arg;
+ emit speedLimitChanged(arg);
+ }
+}
+
+private:
+qreal m_speedLimit;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPEEDLIMITAFFECTOR_H
diff --git a/src/imports/particles/spriteengine.cpp b/src/imports/particles/spriteengine.cpp
new file mode 100644
index 0000000000..b324f7af22
--- /dev/null
+++ b/src/imports/particles/spriteengine.cpp
@@ -0,0 +1,333 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spriteengine.h"
+#include "spritestate.h"
+#include <QDebug>
+#include <QPainter>
+#include <QSet>
+#include <QtOpenGL>
+
+QT_BEGIN_NAMESPACE
+
+SpriteEngine::SpriteEngine(QObject *parent) :
+ QObject(parent), m_timeOffset(0)
+{
+ //Default size 1
+ setCount(1);
+ m_advanceTime.start();
+}
+
+SpriteEngine::SpriteEngine(QList<SpriteState*> states, QObject *parent) :
+ QObject(parent), m_states(states), m_timeOffset(0)
+{
+ //Default size 1
+ setCount(1);
+ m_advanceTime.start();
+}
+
+SpriteEngine::~SpriteEngine()
+{
+}
+
+int SpriteEngine::maxFrames()
+{
+ int max = 0;
+ foreach(SpriteState* s, m_states)
+ if(s->frames() > max)
+ max = s->frames();
+ return max;
+}
+
+void SpriteEngine::setGoal(int state, int sprite, bool jump)
+{
+ if(sprite >= m_sprites.count() || state >= m_states.count())
+ return;
+ if(!jump){
+ m_goals[sprite] = state;
+ return;
+ }
+
+ if(m_sprites[sprite] == state)
+ return;//Already there
+ m_sprites[sprite] = state;
+ m_goals[sprite] = -1;
+ restartSprite(sprite);
+ return;
+}
+
+QImage SpriteEngine::assembledImage()
+{
+ int frameHeight = 0;
+ int frameWidth = 0;
+ m_maxFrames = 0;
+
+ int maxSize;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
+
+ foreach(SpriteState* state, m_states){
+ if(state->frames() > m_maxFrames)
+ m_maxFrames = state->frames();
+
+ QImage img(state->source().toLocalFile());
+ if (img.isNull()) {
+ qWarning() << "SpriteEngine: loading image failed..." << state->source().toLocalFile();
+ return QImage();
+ }
+
+ if(frameWidth){
+ if(img.width() / state->frames() != frameWidth){
+ qWarning() << "SpriteEngine: Irregular frame width..." << state->source().toLocalFile();
+ return QImage();
+ }
+ }else{
+ frameWidth = img.width() / state->frames();
+ }
+ if(img.width() > maxSize){
+ qWarning() << "SpriteEngine: Animation too wide..." << state->source().toLocalFile();
+ return QImage();
+ }
+
+ if(frameHeight){
+ if(img.height()!=frameHeight){
+ qWarning() << "SpriteEngine: Irregular frame height..." << state->source().toLocalFile();
+ return QImage();
+ }
+ }else{
+ frameHeight = img.height();
+ }
+
+ if(img.height() > maxSize){
+ qWarning() << "SpriteEngine: Animation too tall..." << state->source().toLocalFile();
+ return QImage();
+ }
+ }
+
+ QImage image(frameWidth * m_maxFrames, frameHeight * m_states.count(), QImage::Format_ARGB32);
+ image.fill(0);
+ QPainter p(&image);
+ int y = 0;
+ foreach(SpriteState* state, m_states){
+ QImage img(state->source().toLocalFile());
+ p.drawImage(0,y,img);
+ y += frameHeight;
+ }
+
+ if(image.height() > maxSize){
+ qWarning() << "SpriteEngine: Too many animations to fit in one texture...";
+ return QImage();
+ }
+ return image;
+}
+
+void SpriteEngine::setCount(int c)
+{
+ m_sprites.resize(c);
+ m_goals.resize(c);
+ m_startTimes.resize(c);
+}
+
+void SpriteEngine::startSprite(int index)
+{
+ if(index >= m_sprites.count())
+ return;
+ m_sprites[index] = 0;
+ m_goals[index] = -1;
+ restartSprite(index);
+}
+
+void SpriteEngine::restartSprite(int index)
+{
+ m_startTimes[index] = m_timeOffset + m_advanceTime.elapsed();
+ int time = m_states[m_sprites[index]]->duration() * m_states[m_sprites[index]]->frames() + m_startTimes[index];
+ for(int i=0; i<m_stateUpdates.count(); i++)
+ m_stateUpdates[i].second.removeAll(index);
+ addToUpdateList(time, index);
+}
+
+uint SpriteEngine::updateSprites(uint time)
+{
+ //Sprite State Update;
+ while(!m_stateUpdates.isEmpty() && time >= m_stateUpdates.first().first){
+ foreach(int idx, m_stateUpdates.first().second){
+ if(idx >= m_sprites.count())
+ continue;//TODO: Proper fix(because this does happen and I'm just ignoring it)
+ int stateIdx = m_sprites[idx];
+ int nextIdx = -1;
+ int goalPath = goalSeek(stateIdx, idx);
+ if(goalPath == -1){//Random
+ qreal r =(qreal) qrand() / (qreal) RAND_MAX;
+ qreal total = 0.0;
+ for(QVariantMap::const_iterator iter=m_states[stateIdx]->m_to.constBegin();
+ iter!=m_states[stateIdx]->m_to.constEnd(); iter++)
+ total += (*iter).toReal();
+ r*=total;
+ for(QVariantMap::const_iterator iter= m_states[stateIdx]->m_to.constBegin();
+ iter!=m_states[stateIdx]->m_to.constEnd(); iter++){
+ if(r < (*iter).toReal()){
+ bool superBreak = false;
+ for(int i=0; i<m_states.count(); i++){
+ if(m_states[i]->name() == iter.key()){
+ nextIdx = i;
+ superBreak = true;
+ break;
+ }
+ }
+ if(superBreak)
+ break;
+ }
+ r -= (*iter).toReal();
+ }
+ }else{//Random out of shortest paths to goal
+ nextIdx = goalPath;
+ }
+ if(nextIdx == -1)//No to states means stay here
+ nextIdx = stateIdx;
+
+ m_sprites[idx] = nextIdx;
+ m_startTimes[idx] = time;
+ //TODO: emit something?
+ addToUpdateList((m_states[nextIdx]->duration() * m_states[nextIdx]->frames()) + time, idx);
+ }
+ m_stateUpdates.pop_front();
+ }
+
+ m_timeOffset = time;
+ m_advanceTime.start();
+ if(m_stateUpdates.isEmpty())
+ return -1;
+ return m_stateUpdates.first().first;
+}
+
+int SpriteEngine::goalSeek(int curIdx, int spriteIdx, int dist)
+{
+ QString goalName;
+ if(m_goals[spriteIdx] != -1)
+ goalName = m_states[m_goals[spriteIdx]]->name();
+ else
+ goalName = m_globalGoal;
+ if(goalName.isEmpty())
+ return -1;
+ //TODO: caching instead of excessively redoing iterative deepening (which was chosen arbitarily anyways)
+ // Paraphrased - implement in an *efficient* manner
+ for(int i=0; i<m_states.count(); i++)
+ if(m_states[curIdx]->name() == goalName)
+ return curIdx;
+ if(dist < 0)
+ dist = m_states.count();
+ SpriteState* curState = m_states[curIdx];
+ for(QVariantMap::const_iterator iter = curState->m_to.constBegin();
+ iter!=curState->m_to.constEnd(); iter++){
+ if(iter.key() == goalName)
+ for(int i=0; i<m_states.count(); i++)
+ if(m_states[i]->name() == goalName)
+ return i;
+ }
+ QSet<int> options;
+ for(int i=1; i<dist; i++){
+ for(QVariantMap::const_iterator iter = curState->m_to.constBegin();
+ iter!=curState->m_to.constEnd(); iter++){
+ int option = -1;
+ for(int j=0; j<m_states.count(); j++)//One place that could be a lot more efficient...
+ if(m_states[j]->name() == iter.key())
+ if(goalSeek(j, spriteIdx, i) != -1)
+ option = j;
+ if(option != -1)
+ options << option;
+ }
+ if(!options.isEmpty()){
+ if(options.count()==1)
+ return *(options.begin());
+ int option = -1;
+ qreal r =(qreal) qrand() / (qreal) RAND_MAX;
+ qreal total;
+ for(QSet<int>::const_iterator iter=options.constBegin();
+ iter!=options.constEnd(); iter++)
+ total += curState->m_to.value(m_states[(*iter)]->name()).toReal();
+ r *= total;
+ for(QVariantMap::const_iterator iter = curState->m_to.constBegin();
+ iter!=curState->m_to.constEnd(); iter++){
+ bool superContinue = true;
+ for(int j=0; j<m_states.count(); j++)
+ if(m_states[j]->name() == iter.key())
+ if(options.contains(j))
+ superContinue = false;
+ if(superContinue)
+ continue;
+ if(r < (*iter).toReal()){
+ bool superBreak = false;
+ for(int j=0; j<m_states.count(); j++){
+ if(m_states[j]->name() == iter.key()){
+ option = j;
+ superBreak = true;
+ break;
+ }
+ }
+ if(superBreak)
+ break;
+ }
+ r-=(*iter).toReal();
+ }
+ return option;
+ }
+ }
+ return -1;
+}
+
+void SpriteEngine::addToUpdateList(uint t, int idx)
+{
+ for(int i=0; i<m_stateUpdates.count(); i++){
+ if(m_stateUpdates[i].first==t){
+ m_stateUpdates[i].second << idx;
+ return;
+ }else if(m_stateUpdates[i].first > t){
+ QList<int> tmpList;
+ tmpList << idx;
+ m_stateUpdates.insert(i, qMakePair(t, tmpList));
+ return;
+ }
+ }
+ QList<int> tmpList;
+ tmpList << idx;
+ m_stateUpdates << qMakePair(t, tmpList);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/spriteengine.h b/src/imports/particles/spriteengine.h
new file mode 100644
index 0000000000..76a2e29745
--- /dev/null
+++ b/src/imports/particles/spriteengine.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITEENGINE_H
+#define SPRITEENGINE_H
+
+#include <QObject>
+#include <QVector>
+#include <QTimer>
+#include <QTime>
+#include <QList>
+#include <QDeclarativeListProperty>
+#include <QImage>
+#include <QPair>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class SpriteState;
+
+class SpriteEngine : public QObject
+{
+ Q_OBJECT
+ //TODO: Optimize single sprite case
+ Q_PROPERTY(QDeclarativeListProperty<SpriteState> sprites READ sprites)
+ Q_PROPERTY(QString globalGoal READ globalGoal WRITE setGlobalGoal NOTIFY globalGoalChanged)
+public:
+ explicit SpriteEngine(QObject *parent = 0);
+ SpriteEngine(QList<SpriteState*> sprites, QObject *parent=0);
+ ~SpriteEngine();
+
+ QDeclarativeListProperty<SpriteState> sprites()
+ {
+ return QDeclarativeListProperty<SpriteState>(this, m_states);
+ }
+ QString globalGoal() const
+ {
+ return m_globalGoal;
+ }
+
+ int count() const {return m_sprites.count();}
+ void setCount(int c);
+
+ int spriteState(int sprite=0) {return m_sprites[sprite];}
+ int spriteStart(int sprite=0) {return m_startTimes[sprite];}
+ int stateIndex(SpriteState* s){return m_states.indexOf(s);}
+ SpriteState* state(int idx){return m_states[idx];}
+ int stateCount() {return m_states.count();}
+ int maxFrames();
+
+ void setGoal(int state, int sprite=0, bool jump=false);
+ QImage assembledImage();
+
+ void startSprite(int index=0);
+
+signals:
+
+ void globalGoalChanged(QString arg);
+
+public slots:
+ void setGlobalGoal(QString arg)
+ {
+ if (m_globalGoal != arg) {
+ m_globalGoal = arg;
+ emit globalGoalChanged(arg);
+ }
+ }
+
+ uint updateSprites(uint time);
+
+private:
+ void restartSprite(int sprite);
+ void addToUpdateList(uint t, int idx);
+ int goalSeek(int curState, int spriteIdx, int dist=-1);
+ QList<SpriteState*> m_states;
+ QVector<int> m_sprites;//int is the index in m_states of the current state
+ QVector<int> m_goals;
+ QVector<int> m_startTimes;
+ QList<QPair<uint, QList<int> > > m_stateUpdates;//### This could be done faster
+
+ QTime m_advanceTime;
+ uint m_timeOffset;
+ QString m_globalGoal;
+ int m_maxFrames;
+};
+
+//Common use is to have your own list property which is transparently an engine
+inline void spriteAppend(QDeclarativeListProperty<SpriteState> *p, SpriteState* s)
+{
+ reinterpret_cast<QList<SpriteState *> *>(p->data)->append(s);
+ p->object->metaObject()->invokeMethod(p->object, "createEngine");
+}
+
+inline SpriteState* spriteAt(QDeclarativeListProperty<SpriteState> *p, int idx)
+{
+ return reinterpret_cast<QList<SpriteState *> *>(p->data)->at(idx);
+}
+
+inline void spriteClear(QDeclarativeListProperty<SpriteState> *p)
+{
+ reinterpret_cast<QList<SpriteState *> *>(p->data)->clear();
+ p->object->metaObject()->invokeMethod(p->object, "createEngine");
+}
+
+inline int spriteCount(QDeclarativeListProperty<SpriteState> *p)
+{
+ return reinterpret_cast<QList<SpriteState *> *>(p->data)->count();
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPRITEENGINE_H
diff --git a/src/imports/particles/spritegoalaffector.cpp b/src/imports/particles/spritegoalaffector.cpp
new file mode 100644
index 0000000000..2bd56c4a07
--- /dev/null
+++ b/src/imports/particles/spritegoalaffector.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spritegoalaffector.h"
+#include "spriteparticle.h"
+#include "spriteengine.h"
+#include "spritestate.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+SpriteGoalAffector::SpriteGoalAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_goalIdx(-1), m_jump(false)
+{
+}
+
+void SpriteGoalAffector::updateStateIndex(SpriteEngine* e)
+{
+ m_lastEngine = e;
+ for(int i=0; i<e->stateCount(); i++){
+ if(e->state(i)->name() == m_goalState){
+ m_goalIdx = i;
+ return;
+ }
+ }
+ m_goalIdx = -1;//Can't find it
+}
+
+void SpriteGoalAffector::setGoalState(QString arg)
+{
+ if (m_goalState != arg) {
+ m_goalState = arg;
+ emit goalStateChanged(arg);
+ if(m_goalState.isEmpty())
+ m_goalIdx = -1;
+ else
+ m_goalIdx = -2;
+ }
+}
+
+bool SpriteGoalAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ //TODO: Affect all engines
+ SpriteEngine *engine = 0;
+ foreach(ParticleType *p, m_system->m_groupData[d->group]->types)
+ if(qobject_cast<SpriteParticle*>(p))
+ engine = qobject_cast<SpriteParticle*>(p)->spriteEngine();
+ if(!engine)
+ return false;
+
+ if(m_goalIdx == -2 || engine != m_lastEngine)
+ updateStateIndex(engine);
+ if(engine->spriteState(d->particleIndex) != m_goalIdx){
+ engine->setGoal(m_goalIdx, d->particleIndex, m_jump);
+ emit affected(QPointF(d->curX(), d->curY()));//###Expensive if unconnected? Move to Affector?
+ return true; //Doesn't affect particle data, but necessary for onceOff
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/spritegoalaffector.h b/src/imports/particles/spritegoalaffector.h
new file mode 100644
index 0000000000..3a51562be2
--- /dev/null
+++ b/src/imports/particles/spritegoalaffector.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITEGOALAFFECTOR_H
+#define SPRITEGOALAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class SpriteEngine;
+
+class SpriteGoalAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(QString goalState READ goalState WRITE setGoalState NOTIFY goalStateChanged)
+ Q_PROPERTY(bool jump READ jump WRITE setJump NOTIFY jumpChanged)
+public:
+ explicit SpriteGoalAffector(QSGItem *parent = 0);
+
+ QString goalState() const
+ {
+ return m_goalState;
+ }
+
+ bool jump() const
+ {
+ return m_jump;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void goalStateChanged(QString arg);
+
+ void jumpChanged(bool arg);
+
+ void affected(const QPointF &pos);
+public slots:
+
+void setGoalState(QString arg);
+
+void setJump(bool arg)
+{
+ if (m_jump != arg) {
+ m_jump = arg;
+ emit jumpChanged(arg);
+ }
+}
+
+private:
+ void updateStateIndex(SpriteEngine* e);
+ QString m_goalState;
+ int m_goalIdx;
+ SpriteEngine* m_lastEngine;
+ bool m_jump;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPRITEGOALAFFECTOR_H
diff --git a/src/imports/particles/spriteimage.cpp b/src/imports/particles/spriteimage.cpp
new file mode 100644
index 0000000000..b0f8564f7b
--- /dev/null
+++ b/src/imports/particles/spriteimage.cpp
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spriteimage.h"
+#include "spritestate.h"
+#include "spriteengine.h"
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgengine.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include <cmath>
+#include <qmath.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+class SpriteMaterial : public QSGMaterial
+{
+public:
+ SpriteMaterial();
+ virtual ~SpriteMaterial();
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const SpriteMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+
+ qreal timestamp;
+ qreal timelength;
+ int framecount;
+ int animcount;
+ int width;
+ int height;
+};
+
+SpriteMaterial::SpriteMaterial()
+ : timestamp(0)
+ , timelength(1)
+ , framecount(1)
+ , animcount(1)
+ , width(0)
+ , height(0)
+{
+ setFlag(Blending, true);
+}
+
+SpriteMaterial::~SpriteMaterial()
+{
+ delete texture;
+}
+
+class SpriteMaterialData : public QSGMaterialShader
+{
+public:
+ SpriteMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/spriteimagevertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/spriteimagefragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ m_program.setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ SpriteMaterial *m = static_cast<SpriteMaterial *>(newEffect);
+ m->texture->bind();
+
+ m_program.setUniformValue(m_opacity_id, state.opacity());
+ m_program.setUniformValue(m_timestamp_id, (float) m->timestamp);
+ m_program.setUniformValue(m_framecount_id, (float) m->framecount);
+ m_program.setUniformValue(m_animcount_id, (float) m->animcount);
+ m_program.setUniformValue(m_width_id, (float) m->width);
+ m_program.setUniformValue(m_height_id, (float) m->height);
+
+ if (state.isMatrixDirty())
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = m_program.uniformLocation("matrix");
+ m_opacity_id = m_program.uniformLocation("opacity");
+ m_timestamp_id = m_program.uniformLocation("timestamp");
+ m_framecount_id = m_program.uniformLocation("framecount");
+ m_animcount_id = m_program.uniformLocation("animcount");
+ m_width_id = m_program.uniformLocation("width");
+ m_height_id = m_program.uniformLocation("height");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vTex",
+ "vAnimData",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+ int m_framecount_id;
+ int m_animcount_id;
+ int m_width_id;
+ int m_height_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float SpriteMaterialData::chunkOfBytes[1024];
+
+QSGMaterialShader *SpriteMaterial::createShader() const
+{
+ return new SpriteMaterialData;
+}
+
+struct SpriteVertex {
+ float tx;
+ float ty;
+ float animIdx;
+ float frameDuration;
+ float frameCount;
+ float animT;
+};
+
+struct SpriteVertices {
+ SpriteVertex v1;
+ SpriteVertex v2;
+ SpriteVertex v3;
+ SpriteVertex v4;
+};
+
+SpriteImage::SpriteImage(QSGItem *parent) :
+ QSGItem(parent)
+ , m_node(0)
+ , m_material(0)
+ , m_spriteEngine(0)
+ , m_pleaseReset(false)
+ , m_running(true)
+{
+ setFlag(ItemHasContents);
+ connect(this, SIGNAL(runningChanged(bool)),
+ this, SLOT(update()));
+}
+
+QDeclarativeListProperty<SpriteState> SpriteImage::sprites()
+{
+ return QDeclarativeListProperty<SpriteState>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
+}
+
+void SpriteImage::createEngine()
+{
+ //TODO: delay until component complete
+ if(m_spriteEngine)
+ delete m_spriteEngine;
+ if(m_sprites.count())
+ m_spriteEngine = new SpriteEngine(m_sprites, this);
+ else
+ m_spriteEngine = 0;
+ reset();
+}
+
+static QSGGeometry::Attribute SpriteImage_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // tex
+ { 1, 4, GL_FLOAT } // animData
+};
+
+static QSGGeometry::AttributeSet SpriteImage_AttributeSet =
+{
+ 2, // Attribute Count
+ (4 + 2) * sizeof(float),
+ SpriteImage_Attributes
+};
+
+QSGGeometryNode* SpriteImage::buildNode()
+{
+ if (!m_spriteEngine) {
+ qWarning() << "SpriteImage: No sprite engine...";
+ return 0;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ m_material = new SpriteMaterial();
+
+ QImage image = m_spriteEngine->assembledImage();
+ if(image.isNull())
+ return 0;
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+ m_material->framecount = m_spriteEngine->maxFrames();
+
+ int vCount = 4;
+ int iCount = 6;
+ QSGGeometry *g = new QSGGeometry(SpriteImage_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ SpriteVertices *p = (SpriteVertices *) g->vertexData();
+ p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = 0;
+ p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = 0;
+ SpriteState* state = m_spriteEngine->state(0);
+ p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = state->frames();
+ p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = state->duration();
+ m_spriteEngine->startSprite(0);
+
+ p->v1.tx = 0;
+ p->v1.ty = 0;
+
+ p->v2.tx = 1.0;
+ p->v2.ty = 0;
+
+ p->v3.tx = 0;
+ p->v3.ty = 1.0;
+
+ p->v4.tx = 1.0;
+ p->v4.ty = 1.0;
+
+ quint16 *indices = g->indexDataAsUShort();
+ indices[0] = 0;
+ indices[1] = 1;
+ indices[2] = 2;
+ indices[3] = 1;
+ indices[4] = 3;
+ indices[5] = 2;
+
+
+ m_timestamp.start();
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+ return m_node;
+}
+
+void SpriteImage::reset()
+{
+ m_pleaseReset = true;
+}
+
+QSGNode *SpriteImage::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ delete m_node;
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ prepareNextFrame();
+
+ if(m_running){
+ update();
+ if (m_node)
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void SpriteImage::prepareNextFrame()
+{
+ if (m_node == 0)
+ m_node = buildNode();
+ if (m_node == 0) //error creating node
+ return;
+
+ uint timeInt = m_timestamp.elapsed();
+ qreal time = timeInt / 1000.;
+ m_material->timestamp = time;
+ m_material->animcount = m_spriteEngine->stateCount();
+ m_material->height = height();
+ m_material->width = width();
+
+ //Advance State
+ SpriteVertices *p = (SpriteVertices *) m_node->geometry()->vertexData();
+ m_spriteEngine->updateSprites(timeInt);
+ int curIdx = m_spriteEngine->spriteState();
+ if(curIdx != p->v1.animIdx){
+ p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = curIdx;
+ p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = m_spriteEngine->spriteStart()/1000.0;
+ p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->state(curIdx)->frames();
+ p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = m_spriteEngine->state(curIdx)->duration();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/spriteimage.h b/src/imports/particles/spriteimage.h
new file mode 100644
index 0000000000..cd73c97333
--- /dev/null
+++ b/src/imports/particles/spriteimage.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITEIMAGE_H
+#define SPRITEIMAGE_H
+
+#include <QSGItem>
+#include <QTime>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGContext;
+class SpriteState;
+class SpriteEngine;
+class QSGGeometryNode;
+class SpriteMaterial;
+class SpriteImage : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged)
+ //###try to share similar spriteEngines for less overhead?
+ Q_PROPERTY(QDeclarativeListProperty<SpriteState> sprites READ sprites)
+ Q_CLASSINFO("DefaultProperty", "sprites")
+
+public:
+ explicit SpriteImage(QSGItem *parent = 0);
+
+ QDeclarativeListProperty<SpriteState> sprites();
+
+ bool running() const
+ {
+ return m_running;
+ }
+
+signals:
+
+
+ void runningChanged(bool arg);
+
+public slots:
+
+void setRunning(bool arg)
+{
+ if (m_running != arg) {
+ m_running = arg;
+ emit runningChanged(arg);
+ }
+}
+
+private slots:
+ void createEngine();
+protected:
+ void reset();
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+private:
+ void prepareNextFrame();
+ QSGGeometryNode* buildNode();
+ QSGGeometryNode *m_node;
+ SpriteMaterial *m_material;
+ QList<SpriteState*> m_sprites;
+ SpriteEngine* m_spriteEngine;
+ QTime m_timestamp;
+ int m_maxFrames;
+ bool m_pleaseReset;
+ bool m_running;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPRITEIMAGE_H
diff --git a/src/imports/particles/spriteparticle.cpp b/src/imports/particles/spriteparticle.cpp
new file mode 100644
index 0000000000..dcd8f4a89b
--- /dev/null
+++ b/src/imports/particles/spriteparticle.cpp
@@ -0,0 +1,450 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spriteparticle.h"
+#include "spritestate.h"
+#include "spriteengine.h"
+#include "particleemitter.h"
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgengine.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include <cmath>
+#include <qmath.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+class SpriteParticlesMaterial : public QSGMaterial
+{
+public:
+ SpriteParticlesMaterial();
+ virtual ~SpriteParticlesMaterial();
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const SpriteParticlesMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+
+ qreal timestamp;
+ int framecount;
+ int animcount;
+};
+
+SpriteParticlesMaterial::SpriteParticlesMaterial()
+ : timestamp(0)
+ , framecount(1)
+ , animcount(1)
+{
+ setFlag(Blending, true);
+}
+
+SpriteParticlesMaterial::~SpriteParticlesMaterial()
+{
+ delete texture;
+}
+
+class SpriteParticlesMaterialData : public QSGMaterialShader
+{
+public:
+ SpriteParticlesMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/spritevertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/spritefragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ m_program.setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ SpriteParticlesMaterial *m = static_cast<SpriteParticlesMaterial *>(newEffect);
+ m->texture->bind();
+
+ m_program.setUniformValue(m_opacity_id, state.opacity());
+ m_program.setUniformValue(m_timestamp_id, (float) m->timestamp);
+ m_program.setUniformValue(m_framecount_id, (float) m->framecount);
+ m_program.setUniformValue(m_animcount_id, (float) m->animcount);
+
+ if (state.isMatrixDirty())
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = m_program.uniformLocation("matrix");
+ m_opacity_id = m_program.uniformLocation("opacity");
+ m_timestamp_id = m_program.uniformLocation("timestamp");
+ m_framecount_id = m_program.uniformLocation("framecount");
+ m_animcount_id = m_program.uniformLocation("animcount");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ "vAnimData",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+ int m_framecount_id;
+ int m_animcount_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float SpriteParticlesMaterialData::chunkOfBytes[1024];
+
+QSGMaterialShader *SpriteParticlesMaterial::createShader() const
+{
+ return new SpriteParticlesMaterialData;
+}
+
+struct SpriteParticleVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ float animIdx;
+ float frameDuration;
+ float frameCount;
+ float animT;
+};
+
+struct SpriteParticleVertices {
+ SpriteParticleVertex v1;
+ SpriteParticleVertex v2;
+ SpriteParticleVertex v3;
+ SpriteParticleVertex v4;
+};
+
+SpriteParticle::SpriteParticle(QSGItem *parent) :
+ ParticleType(parent)
+ , m_node(0)
+ , m_material(0)
+ , m_spriteEngine(0)
+{
+ setFlag(ItemHasContents);
+ }
+QDeclarativeListProperty<SpriteState> SpriteParticle::sprites()
+{
+ return QDeclarativeListProperty<SpriteState>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
+}
+
+void SpriteParticle::createEngine()
+{
+ if(m_spriteEngine)
+ delete m_spriteEngine;
+ if(m_sprites.count())
+ m_spriteEngine = new SpriteEngine(m_sprites, this);
+ else
+ m_spriteEngine = 0;
+ reset();//###this is probably out of updatePaintNode and shouldn't be
+}
+
+void SpriteParticle::setCount(int c)
+{
+ ParticleType::setCount(c);
+ m_pleaseReset = true;
+}
+
+static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_FLOAT } // Colors
+};
+
+static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
+{
+ 5, // Attribute Count
+ (2 + 2 + 4 + 4 + 4) * sizeof(float),
+ SpriteParticle_Attributes
+};
+
+
+
+QSGGeometryNode* SpriteParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ qWarning() << "SpriteParticle: too many particles...";
+ return 0;
+ }
+
+ if (m_count * 4 == 0) {
+ qWarning() << "SpriteParticle: No particles...";
+ return 0;
+ }
+
+ if (!m_spriteEngine) {
+ qWarning() << "SpriteParticle: No sprite engine...";
+ return 0;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ m_material = new SpriteParticlesMaterial();
+
+ QImage image = m_spriteEngine->assembledImage();
+ if(image.isNull())
+ return 0;
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+ m_material->framecount = m_spriteEngine->maxFrames();
+ m_spriteEngine->setCount(m_count);
+
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+ QSGGeometry *g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ SpriteParticleVertex *vertices = (SpriteParticleVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = 0;
+ vertices[i].y = 0;
+ vertices[i].t = -1;
+ vertices[i].lifeSpan = -1;
+ vertices[i].size = 0;
+ vertices[i].endSize = 0;
+ vertices[i].sx = 0;
+ vertices[i].sy = 0;
+ vertices[i].ax = 0;
+ vertices[i].ay = 0;
+ vertices[i].animIdx = 0;
+ vertices[i].frameDuration = 1;
+ vertices[i].frameCount = 1;
+ vertices[i].animT = -1;
+
+ }
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1.0;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1.0;
+
+ vertices[3].tx = 1.0;
+ vertices[3].ty = 1.0;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+ m_last_particle = 0;
+ return m_node;
+}
+
+void SpriteParticle::vertexCopy(SpriteParticleVertex &b,const ParticleVertex& a)
+{
+ b.x = a.x + m_systemOffset.x();
+ b.y = a.y + m_systemOffset.y();
+ b.t = a.t;
+ b.lifeSpan = a.lifeSpan;
+ b.size = a.size;
+ b.endSize = a.endSize;
+ b.sx = a.sx;
+ b.sy = a.sy;
+ b.ax = a.ax;
+ b.ay = a.ay;
+}
+
+void SpriteParticle::load(ParticleData *d)
+{
+ if (m_node == 0) //error creating node
+ return;
+
+ SpriteParticleVertices *particles = (SpriteParticleVertices *) m_node->geometry()->vertexData();
+ int pos = particleTypeIndex(d);
+ SpriteParticleVertices &p = particles[pos];
+
+ // Initial Sprite State
+ p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = p.v1.t;
+ p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = 0;
+ SpriteState* state = m_spriteEngine->state(0);
+ p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = state->frames();
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = state->duration();
+ m_spriteEngine->startSprite(pos);
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+
+}
+
+void SpriteParticle::reload(ParticleData *d)
+{
+ if (m_node == 0) //error creating node
+ return;
+
+ SpriteParticleVertices *particles = (SpriteParticleVertices *) m_node->geometry()->vertexData();
+ int pos = particleTypeIndex(d);
+ SpriteParticleVertices &p = particles[pos];
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+
+QSGNode *SpriteParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node)
+ delete m_node;
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+ if(m_system&& m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void SpriteParticle::prepareNextFrame()
+{
+ if (m_node == 0){ //TODO: Staggered loading (as emitted) (is it just moving this check to load()?)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ }
+ uint timeStamp = m_system->systemSync(this);
+
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+ m_material->animcount = m_spriteEngine->stateCount();
+
+ //Advance State
+ SpriteParticleVertices *particles = (SpriteParticleVertices *) m_node->geometry()->vertexData();
+ m_spriteEngine->updateSprites(timeStamp);
+ for(int i=0; i<m_count; i++){
+ SpriteParticleVertices &p = particles[i];
+ int curIdx = m_spriteEngine->spriteState(i);
+ if(curIdx != p.v1.animIdx){
+ p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
+ p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
+ p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->state(curIdx)->frames();
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->state(curIdx)->duration();
+ }
+ }
+}
+
+void SpriteParticle::reset()
+{
+ ParticleType::reset();
+ m_pleaseReset = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/spriteparticle.h b/src/imports/particles/spriteparticle.h
new file mode 100644
index 0000000000..ed861f5c5e
--- /dev/null
+++ b/src/imports/particles/spriteparticle.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITEPARTICLE_H
+#define SPRITEPARTICLE_H
+#include "particle.h"
+#include <QDeclarativeListProperty>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class SpriteState;
+class SpriteEngine;
+class QSGGeometryNode;
+class SpriteParticlesMaterial;
+class SpriteParticleVertex;
+
+class SpriteParticle : public ParticleType
+{
+ Q_OBJECT
+ Q_PROPERTY(QDeclarativeListProperty<SpriteState> sprites READ sprites)
+ Q_CLASSINFO("DefaultProperty", "sprites")
+public:
+ explicit SpriteParticle(QSGItem *parent = 0);
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+
+ QDeclarativeListProperty<SpriteState> sprites();
+ SpriteEngine* spriteEngine() {return m_spriteEngine;}
+signals:
+
+public slots:
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void reset();
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+private slots:
+ void createEngine();
+private:
+ QSGGeometryNode *m_node;
+ SpriteParticlesMaterial *m_material;
+
+ int m_particle_duration;
+ int m_last_particle;
+ QTime m_timestamp;
+
+ QList<SpriteState*> m_sprites;
+ SpriteEngine* m_spriteEngine;
+
+ void vertexCopy(SpriteParticleVertex &b,const ParticleVertex& a);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPRITEPARTICLE_H
diff --git a/src/imports/particles/spriteparticles.qrc b/src/imports/particles/spriteparticles.qrc
new file mode 100644
index 0000000000..c0c7a52036
--- /dev/null
+++ b/src/imports/particles/spriteparticles.qrc
@@ -0,0 +1,16 @@
+<RCC>
+ <qresource prefix="/">
+ <file>resources/spritefragment.shader</file>
+ <file>resources/spritevertex.shader</file>
+ <file>resources/ctfragment.shader</file>
+ <file>resources/ctvertex.shader</file>
+ <file>resources/trailsfragment.shader</file>
+ <file>resources/trailsvertex.shader</file>
+ <file>resources/spriteimagefragment.shader</file>
+ <file>resources/spriteimagevertex.shader</file>
+ <file>resources/identitytable.png</file>
+ <file>resources/defaultFadeInOut.png</file>
+ <file>resources/deformablefragment.shader</file>
+ <file>resources/deformablevertex.shader</file>
+ </qresource>
+</RCC>
diff --git a/src/imports/particles/spritestate.cpp b/src/imports/particles/spritestate.cpp
new file mode 100644
index 0000000000..c3cc249fde
--- /dev/null
+++ b/src/imports/particles/spritestate.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spritestate.h"
+
+QT_BEGIN_NAMESPACE
+
+SpriteState::SpriteState(QObject *parent) :
+ QObject(parent)
+ , m_frames(1)
+ , m_duration(1000)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/spritestate.h b/src/imports/particles/spritestate.h
new file mode 100644
index 0000000000..1dbc747ae8
--- /dev/null
+++ b/src/imports/particles/spritestate.h
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITESTATE_H
+#define SPRITESTATE_H
+
+#include <QObject>
+#include <QUrl>
+#include <QVariantMap>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class SpriteState : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY framesChanged)
+ Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+ Q_PROPERTY(int durationVariance READ durationVariance WRITE setDurationVariance NOTIFY durationVarianceChanged)
+ Q_PROPERTY(qreal speedModifiesDuration READ speedModifer WRITE setSpeedModifier NOTIFY speedModifierChanged)
+ Q_PROPERTY(QVariantMap to READ to WRITE setTo NOTIFY toChanged)
+
+public:
+ explicit SpriteState(QObject *parent = 0);
+
+ QUrl source() const
+ {
+ return m_source;
+ }
+
+ int frames() const
+ {
+ return m_frames;
+ }
+
+ int duration() const
+ {
+ return m_duration;
+ }
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ QVariantMap to() const
+ {
+ return m_to;
+ }
+
+ qreal speedModifer() const
+ {
+ return m_speedModifier;
+ }
+
+ int durationVariance() const
+ {
+ return m_durationVariance;
+ }
+
+signals:
+
+ void sourceChanged(QUrl arg);
+
+ void framesChanged(int arg);
+
+ void durationChanged(int arg);
+
+ void nameChanged(QString arg);
+
+ void toChanged(QVariantMap arg);
+
+ void speedModifierChanged(qreal arg);
+
+ void durationVarianceChanged(int arg);
+
+public slots:
+
+ void setSource(QUrl arg)
+ {
+ if (m_source != arg) {
+ m_source = arg;
+ emit sourceChanged(arg);
+ }
+ }
+
+ void setFrames(int arg)
+ {
+ if (m_frames != arg) {
+ m_frames = arg;
+ emit framesChanged(arg);
+ }
+ }
+
+ void setDuration(int arg)
+ {
+ if (m_duration != arg) {
+ m_duration = arg;
+ emit durationChanged(arg);
+ }
+ }
+
+ void setName(QString arg)
+ {
+ if (m_name != arg) {
+ m_name = arg;
+ emit nameChanged(arg);
+ }
+ }
+
+ void setTo(QVariantMap arg)
+ {
+ if (m_to != arg) {
+ m_to = arg;
+ emit toChanged(arg);
+ }
+ }
+
+ void setSpeedModifier(qreal arg)
+ {
+ if (m_speedModifier != arg) {
+ m_speedModifier = arg;
+ emit speedModifierChanged(arg);
+ }
+ }
+
+ void setDurationVariance(int arg)
+ {
+ if (m_durationVariance != arg) {
+ m_durationVariance = arg;
+ emit durationVarianceChanged(arg);
+ }
+ }
+
+private:
+ friend class SpriteParticle;
+ friend class SpriteEngine;
+ QUrl m_source;
+ int m_frames;
+ int m_duration;
+ QString m_name;
+ QVariantMap m_to;
+ qreal m_speedModifier;
+ int m_durationVariance;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // SPRITESTATE_H
diff --git a/src/imports/particles/swarmaffector.cpp b/src/imports/particles/swarmaffector.cpp
new file mode 100644
index 0000000000..513e8a17a7
--- /dev/null
+++ b/src/imports/particles/swarmaffector.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "swarmaffector.h"
+#include "particle.h"
+#include <cmath>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+
+SwarmAffector::SwarmAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_strength(1), m_inited(false)
+{
+ connect(this, SIGNAL(leadersChanged(QStringList)),
+ this, SLOT(updateGroupList()));
+}
+
+void SwarmAffector::ensureInit()
+{
+ if(m_inited)
+ return;
+ m_inited = true;
+ updateGroupList();
+ m_lastPos.resize(m_system->count());
+}
+
+const qreal epsilon = 0.0000001;
+bool SwarmAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ ensureInit();
+ QPointF curPos(d->curX(), d->curY());
+ if(m_leaders.isEmpty() || m_leadGroups.contains(d->group)){
+ m_lastPos[d->systemIndex] = curPos;
+ if(m_leadGroups.contains(d->group))
+ return false;
+ }
+
+ qreal fx = 0.0;
+ qreal fy = 0.0;
+ for(int i=0; i < m_lastPos.count(); i++){
+ if(m_lastPos[i].isNull())
+ continue;
+ QPointF diff = m_lastPos[i] - curPos;
+ qreal r = sqrt(diff.x() * diff.x() + diff.y() * diff.y());
+ if(r == 0.0)
+ continue;
+ qreal f = m_strength * (1/r);
+ if(f < epsilon)
+ continue;
+ qreal theta = atan2(diff.y(), diff.x());
+ fx += cos(theta) * f;
+ fy += sin(theta) * f;
+ }
+ if(!fx && !fy)
+ return false;
+ d->setInstantaneousSX(d->curSX()+fx * dt);
+ d->setInstantaneousSY(d->curSY()+fy * dt);
+ return true;
+}
+
+void SwarmAffector::reset(int systemIdx)
+{
+ if(!m_system)
+ return;
+ if(!m_lastPos[systemIdx].isNull())
+ m_lastPos[systemIdx] = QPointF();
+}
+
+void SwarmAffector::updateGroupList()
+{
+ if(!m_system || !m_system->m_initialized)
+ return;
+ m_leadGroups.clear();
+ foreach(const QString &s, m_leaders)
+ m_leadGroups << m_system->m_groupIds[s];
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/swarmaffector.h b/src/imports/particles/swarmaffector.h
new file mode 100644
index 0000000000..63f77c9294
--- /dev/null
+++ b/src/imports/particles/swarmaffector.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SWARMAFFECTOR_H
+#define SWARMAFFECTOR_H
+#include "particleaffector.h"
+#include <QDeclarativeListProperty>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleType;
+
+class SwarmAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged)
+ Q_PROPERTY(QStringList leaders READ leaders WRITE setLeaders NOTIFY leadersChanged)
+public:
+ explicit SwarmAffector(QSGItem *parent = 0);
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+ virtual void reset(int systemIdx);
+
+ qreal strength() const
+ {
+ return m_strength;
+ }
+
+ QStringList leaders() const
+ {
+ return m_leaders;
+ }
+
+signals:
+
+ void strengthChanged(qreal arg);
+
+ void leadersChanged(QStringList arg);
+
+public slots:
+
+void setStrength(qreal arg)
+{
+ if (m_strength != arg) {
+ m_strength = arg;
+ emit strengthChanged(arg);
+ }
+}
+
+void setLeaders(QStringList arg)
+{
+ if (m_leaders != arg) {
+ m_leaders = arg;
+ emit leadersChanged(arg);
+ }
+}
+
+private:
+ void ensureInit();
+ void mapUpdate(int idx, qreal strength);
+ QVector<QPointF> m_lastPos;
+ qreal m_strength;
+ bool m_inited;
+ QStringList m_leaders;
+ QSet<int> m_leadGroups;
+private slots:
+ void updateGroupList();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SWARMAFFECTOR_H
diff --git a/src/imports/particles/toggleaffector.cpp b/src/imports/particles/toggleaffector.cpp
new file mode 100644
index 0000000000..5e03b17684
--- /dev/null
+++ b/src/imports/particles/toggleaffector.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "toggleaffector.h"
+
+QT_BEGIN_NAMESPACE
+
+ToggleAffector::ToggleAffector(QObject *parent) :
+ ParticleAffector(parent)
+{
+}
+
+bool ToggleAffector::affect(ParticleData *d, qreal dt)
+{
+ if(m_affecting)
+ return m_affector->affect(d, dt);
+ else
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/toggleaffector.h b/src/imports/particles/toggleaffector.h
new file mode 100644
index 0000000000..08e7c0e2eb
--- /dev/null
+++ b/src/imports/particles/toggleaffector.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TOGGLEAFFECTOR_H
+#define TOGGLEAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ToggleAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(bool affecting READ affecting WRITE setAffecting NOTIFY affectingChanged)
+ Q_PROPERTY(ParticleAffector* affector READ affector WRITE affector NOTIFY affectorChanged)
+ Q_CLASSINFO("DefaultProperty", "affector")
+
+public:
+ explicit ToggleAffector(QObject *parent = 0);
+ virtual bool affect(ParticleData *d, qreal dt);
+ bool affecting() const
+ {
+ return m_affecting;
+ }
+
+ ParticleAffector* affector() const
+ {
+ return m_affector;
+ }
+
+signals:
+
+ void affectingChanged(bool arg);
+
+ void affectorChanged(ParticleAffector* arg);
+
+public slots:
+void setAffecting(bool arg)
+{
+ if (m_affecting != arg) {
+ m_affecting = arg;
+ emit affectingChanged(arg);
+ }
+}
+
+void affector(ParticleAffector* arg)
+{
+ if (m_affector != arg) {
+ m_affector = arg;
+ emit affectorChanged(arg);
+ }
+}
+
+private:
+bool m_affecting;
+ParticleAffector* m_affector;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // TOGGLEAFFECTOR_H
diff --git a/src/imports/particles/trailsemitter.cpp b/src/imports/particles/trailsemitter.cpp
new file mode 100644
index 0000000000..2355670801
--- /dev/null
+++ b/src/imports/particles/trailsemitter.cpp
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "trailsemitter.h"
+#include "particlesystem.h"
+#include "particle.h"
+QT_BEGIN_NAMESPACE
+
+TrailsEmitter::TrailsEmitter(QSGItem* parent)
+ : ParticleEmitter(parent)
+ , m_speed_from_movement(0)
+ , m_particle_count(0)
+ , m_reset_last(true)
+ , m_last_timestamp(0)
+ , m_last_emission(0)
+{
+// setFlag(ItemHasContents);
+}
+
+void TrailsEmitter::setSpeedFromMovement(qreal t)
+{
+ if (t == m_speed_from_movement)
+ return;
+ m_speed_from_movement = t;
+ emit speedFromMovementChanged();
+}
+
+void TrailsEmitter::reset()
+{
+ m_reset_last = true;
+}
+
+void TrailsEmitter::emitWindow(int timeStamp)
+{
+ if (m_system == 0)
+ return;
+ if((!m_emitting || !m_particlesPerSecond)&& !m_burstLeft && !m_emitLeft){
+ m_reset_last = true;
+ return;
+ }
+
+ if (m_reset_last) {
+ m_last_emitter = m_last_last_emitter = QPointF(x(), y());
+ m_last_timestamp = timeStamp/1000.;
+ m_last_emission = m_last_timestamp;
+ m_reset_last = false;
+ }
+
+ if(m_burstLeft){
+ m_burstLeft -= timeStamp - m_last_timestamp * 1000.;
+ if(m_burstLeft < 0){
+ if(!m_emitting)
+ timeStamp += m_burstLeft;
+ m_burstLeft = 0;
+ }
+ }
+ qreal time = timeStamp / 1000.;
+
+ qreal particleRatio = 1. / m_particlesPerSecond;
+ qreal pt = m_last_emission;
+
+ qreal opt = pt; // original particle time
+ qreal dt = time - m_last_timestamp; // timestamp delta...
+ if(!dt)
+ dt = 0.000001;
+
+ // emitter difference since last...
+ qreal dex = (x() - m_last_emitter.x());
+ qreal dey = (y() - m_last_emitter.y());
+
+ qreal ax = (m_last_last_emitter.x() + m_last_emitter.x()) / 2;
+ qreal bx = m_last_emitter.x();
+ qreal cx = (x() + m_last_emitter.x()) / 2;
+ qreal ay = (m_last_last_emitter.y() + m_last_emitter.y()) / 2;
+ qreal by = m_last_emitter.y();
+ qreal cy = (y() + m_last_emitter.y()) / 2;
+
+ qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize;
+ qreal emitter_x_offset = m_last_emitter.x() - x();
+ qreal emitter_y_offset = m_last_emitter.y() - y();
+ while (pt < time || m_emitLeft) {
+ //int pos = m_last_particle % m_particle_count;
+ ParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_particle]);
+ if(!datum){//skip this emission
+ if(!m_emitLeft)
+ pt += particleRatio;
+ else
+ --m_emitLeft;
+ continue;
+ }
+ datum->e = this;//###useful?
+ ParticleVertex &p = datum->pv;
+ qreal t = 1 - (pt - opt) / dt;
+ qreal vx =
+ - 2 * ax * (1 - t)
+ + 2 * bx * (1 - 2 * t)
+ + 2 * cx * t;
+ qreal vy =
+ - 2 * ay * (1 - t)
+ + 2 * by * (1 - 2 * t)
+ + 2 * cy * t;
+
+
+ // Particle timestamp
+ p.t = pt;
+ p.lifeSpan = //TODO:Promote to base class?
+ (m_particleDuration
+ + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation))
+ / 1000.0;
+
+ // Particle position
+ QRectF boundsRect(emitter_x_offset + dex * (pt - opt) / dt, emitter_y_offset + dey * (pt - opt) / dt
+ , width(), height());
+ QPointF newPos = effectiveExtruder()->extrude(boundsRect);
+ p.x = newPos.x();
+ p.y = newPos.y();
+
+ // Particle speed
+ const QPointF &speed = m_speed->sample(newPos);
+ p.sx = speed.x()
+ + m_speed_from_movement * vx;
+ p.sy = speed.y()
+ + m_speed_from_movement * vy;
+
+ // Particle acceleration
+ const QPointF &accel = m_acceleration->sample(newPos);
+ p.ax = accel.x();
+ p.ay = accel.y();
+
+ // Particle size
+ float sizeVariation = -m_particleSizeVariation
+ + rand() / float(RAND_MAX) * m_particleSizeVariation * 2;
+
+ float size = qMax((qreal)0.0 , m_particleSize + sizeVariation);
+ float endSize = qMax((qreal)0.0 , sizeAtEnd + sizeVariation);
+
+ p.size = size;// * float(m_emitting);
+ p.endSize = endSize;// * float(m_emitting);
+
+ if(!m_emitLeft)
+ pt += particleRatio;
+ else
+ --m_emitLeft;
+
+ m_system->emitParticle(datum);
+ }
+ m_last_emission = pt;
+
+ m_last_last_last_emitter = m_last_last_emitter;
+ m_last_last_emitter = m_last_emitter;
+ m_last_emitter = QPointF(x(), y());
+ m_last_timestamp = time;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/trailsemitter.h b/src/imports/particles/trailsemitter.h
new file mode 100644
index 0000000000..1ae150c0d2
--- /dev/null
+++ b/src/imports/particles/trailsemitter.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TRAILSEMITTER_H
+#define TRAILSEMITTER_H
+
+#include <QtCore>
+#include <QtGui>
+
+#include "particleemitter.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleTrailsMaterial;
+class QSGGeometryNode;
+
+class TrailsEmitter : public ParticleEmitter
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal speedFromMovement READ speedFromMovement WRITE setSpeedFromMovement NOTIFY speedFromMovementChanged)
+
+public:
+ explicit TrailsEmitter(QSGItem* parent=0);
+ virtual ~TrailsEmitter(){}
+ virtual void emitWindow(int timeStamp);
+
+
+ qreal speedFromMovement() const { return m_speed_from_movement; }
+ void setSpeedFromMovement(qreal s);
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+signals:
+
+ void speedFromMovementChanged();
+
+public slots:
+public:
+ virtual void reset();
+protected:
+
+private:
+
+ qreal m_speed_from_movement;
+
+ // derived values...
+ int m_particle_count;
+ bool m_reset_last;
+ qreal m_last_timestamp;
+ qreal m_last_emission;
+
+ QPointF m_last_emitter;
+ QPointF m_last_last_emitter;
+ QPointF m_last_last_last_emitter;
+
+ qreal m_render_opacity;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // TRAILSEMITTER_H
diff --git a/src/imports/particles/turbulenceaffector.cpp b/src/imports/particles/turbulenceaffector.cpp
new file mode 100644
index 0000000000..d29f09d974
--- /dev/null
+++ b/src/imports/particles/turbulenceaffector.cpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "turbulenceaffector.h"
+#include "particle.h"
+#include <cmath>
+#include <cstdlib>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+
+TurbulenceAffector::TurbulenceAffector(QSGItem *parent) :
+ ParticleAffector(parent),
+ m_strength(10), m_lastT(0), m_frequency(64), m_gridSize(10), m_field(0), m_inited(false)
+{
+ //TODO: Update grid on size change
+}
+
+TurbulenceAffector::~TurbulenceAffector()
+{
+ if (m_field) {
+ for(int i=0; i<m_gridSize; i++)
+ free(m_field[i]);
+ free(m_field);
+ }
+}
+
+static qreal magnitude(qreal x, qreal y)
+{
+ return sqrt(x*x + y*y);
+}
+
+void TurbulenceAffector::setSize(int arg)
+{
+ if (m_gridSize != arg) {
+ if(m_field){ //deallocate and then reallocate grid
+ for(int i=0; i<m_gridSize; i++)
+ free(m_field[i]);
+ free(m_field);
+ m_system = 0;
+ }
+ m_gridSize = arg;
+ emit sizeChanged(arg);
+ }
+}
+
+void TurbulenceAffector::ensureInit()
+{
+ if(m_inited)
+ return;
+ m_inited = true;
+ m_field = (QPointF**)malloc(m_gridSize * sizeof(QPointF*));
+ for(int i=0; i<m_gridSize; i++)
+ m_field[i] = (QPointF*)malloc(m_gridSize * sizeof(QPointF));
+ for(int i=0; i<m_gridSize; i++)
+ for(int j=0; j<m_gridSize; j++)
+ m_field[i][j] = QPointF();
+ m_spacing = QPointF(width()/m_gridSize, height()/m_gridSize);
+ m_magSum = magnitude(m_spacing.x(), m_spacing.y())*2;
+}
+
+void TurbulenceAffector::mapUpdate()
+{
+ QPoint pos(rand() % m_gridSize, rand() % m_gridSize);
+ QPointF vector(m_strength - (((qreal)rand() / RAND_MAX) * m_strength*2),
+ m_strength - (((qreal)rand() / RAND_MAX) * m_strength*2));
+ for(int i = 0; i < m_gridSize; i++){
+ for(int j = 0; j < m_gridSize; j++){
+ qreal dist = magnitude(i-pos.x(), j-pos.y());
+ m_field[i][j] += vector/(dist + 1);
+ if(magnitude(m_field[i][j].x(), m_field[i][j].y()) > m_strength){
+ //Speed limit
+ qreal theta = atan2(m_field[i][j].y(), m_field[i][j].x());
+ m_field[i][j].setX(m_strength * cos(theta));
+ m_field[i][j].setY(m_strength * sin(theta));
+ }
+ }
+ }
+}
+
+
+void TurbulenceAffector::affectSystem(qreal dt)
+{
+ if(!m_system || !m_active)
+ return;
+ ensureInit();
+ qreal period = 1.0/m_frequency;
+ qreal time = m_system->m_timeInt / 1000.0;
+ while( m_lastT < time ){
+ mapUpdate();
+ m_lastT += period;
+ }
+
+ foreach(ParticleData *d, m_system->m_data){
+ if(!d || !activeGroup(d->group))
+ return;
+ qreal fx = 0.0;
+ qreal fy = 0.0;
+ QPointF pos = QPointF(d->curX() - x(), d->curY() - y());//TODO: Offset
+ QPointF nodePos = QPointF(pos.x() / m_spacing.x(), pos.y() / m_spacing.y());
+ QSet<QPair<int, int> > nodes;
+ nodes << qMakePair((int)ceil(nodePos.x()), (int)ceil(nodePos.y()));
+ nodes << qMakePair((int)ceil(nodePos.x()), (int)floor(nodePos.y()));
+ nodes << qMakePair((int)floor(nodePos.x()), (int)ceil(nodePos.y()));
+ nodes << qMakePair((int)floor(nodePos.x()), (int)floor(nodePos.y()));
+ typedef QPair<int, int> intPair;
+ foreach(const intPair &p, nodes){
+ if(!QRect(0,0,m_gridSize-1,m_gridSize-1).contains(QPoint(p.first, p.second)))
+ continue;
+ qreal dist = magnitude(pos.x() - p.first*m_spacing.x(), pos.y() - p.second*m_spacing.y());//TODO: Mathematically valid
+ fx += m_field[p.first][p.second].x() * ((m_magSum - dist)/m_magSum);//Proportionally weight nodes
+ fy += m_field[p.first][p.second].y() * ((m_magSum - dist)/m_magSum);
+ }
+ if(fx || fy){
+ d->setInstantaneousSX(d->curSX()+ fx * dt);
+ d->setInstantaneousSY(d->curSY()+ fy * dt);
+ m_system->m_needsReset << d;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/turbulenceaffector.h b/src/imports/particles/turbulenceaffector.h
new file mode 100644
index 0000000000..2dc2ddcdfd
--- /dev/null
+++ b/src/imports/particles/turbulenceaffector.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TURBULENCEAFFECTOR_H
+#define TURBULENCEAFFECTOR_H
+#include "particleaffector.h"
+#include <QDeclarativeListProperty>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleType;
+
+class TurbulenceAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(int strength READ strength WRITE setStrength NOTIFY strengthChanged)
+ Q_PROPERTY(int frequency READ frequency WRITE setFrequency NOTIFY frequencyChanged)
+ Q_PROPERTY(int gridSize READ size WRITE setSize NOTIFY sizeChanged)
+public:
+ explicit TurbulenceAffector(QSGItem *parent = 0);
+ ~TurbulenceAffector();
+ virtual void affectSystem(qreal dt);
+
+ int strength() const
+ {
+ return m_strength;
+ }
+
+ int frequency() const
+ {
+ return m_frequency;
+ }
+
+ int size() const
+ {
+ return m_gridSize;
+ }
+
+signals:
+
+ void strengthChanged(int arg);
+
+ void frequencyChanged(int arg);
+
+ void sizeChanged(int arg);
+
+public slots:
+
+void setStrength(int arg)
+{
+ if (m_strength != arg) {
+ m_strength = arg;
+ emit strengthChanged(arg);
+ }
+}
+
+void setFrequency(int arg)
+{
+ if (m_frequency != arg) {
+ m_frequency = arg;
+ emit frequencyChanged(arg);
+ }
+}
+
+void setSize(int arg);
+
+private:
+ void ensureInit();
+ void mapUpdate();
+ int m_strength;
+ qreal m_lastT;
+ int m_frequency;
+ int m_gridSize;
+ QPointF** m_field;
+ QPointF m_spacing;
+ qreal m_magSum;
+ bool m_inited;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // TURBULENCEAFFECTOR_H
diff --git a/src/imports/particles/varyingvector.cpp b/src/imports/particles/varyingvector.cpp
new file mode 100644
index 0000000000..ab09f47f79
--- /dev/null
+++ b/src/imports/particles/varyingvector.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "varyingvector.h"
+
+QT_BEGIN_NAMESPACE
+
+VaryingVector::VaryingVector(QObject *parent) :
+ QObject(parent)
+{
+}
+
+const QPointF &VaryingVector::sample(const QPointF &from)
+{
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/varyingvector.h b/src/imports/particles/varyingvector.h
new file mode 100644
index 0000000000..9f80366d2e
--- /dev/null
+++ b/src/imports/particles/varyingvector.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VARYINGVECTOR_H
+#define VARYINGVECTOR_H
+
+#include <QObject>
+#include <QPointF>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class VaryingVector : public QObject
+{
+ Q_OBJECT
+public:
+ explicit VaryingVector(QObject *parent = 0);
+
+ virtual const QPointF &sample(const QPointF &from);
+signals:
+
+public slots:
+
+protected:
+ QPointF m_ret;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // VARYINGVECTOR_H
diff --git a/src/imports/particles/wanderaffector.cpp b/src/imports/particles/wanderaffector.cpp
new file mode 100644
index 0000000000..4d3ba5f7ce
--- /dev/null
+++ b/src/imports/particles/wanderaffector.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "wanderaffector.h"
+#include "particlesystem.h"//for ParticlesVertices
+QT_BEGIN_NAMESPACE
+
+WanderAffector::WanderAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+ m_needsReset = true;
+}
+
+WanderAffector::~WanderAffector()
+{
+ for(QHash<int, WanderData*>::const_iterator iter=m_wanderData.constBegin();
+ iter != m_wanderData.constEnd(); iter++)
+ delete (*iter);
+}
+
+WanderData* WanderAffector::getData(int idx)
+{
+ if(m_wanderData.contains(idx))
+ return m_wanderData[idx];
+ WanderData* d = new WanderData;
+ d->x_vel = 0;
+ d->y_vel = 0;
+ d->x_peak = m_xVariance;
+ d->y_peak = m_yVariance;
+ d->x_var = m_pace * qreal(qrand()) / RAND_MAX;
+ d->y_var = m_pace * qreal(qrand()) / RAND_MAX;
+
+ m_wanderData.insert(idx, d);
+ return d;
+}
+
+void WanderAffector::reset(int systemIdx)
+{
+ if(m_wanderData.contains(systemIdx))
+ delete m_wanderData[systemIdx];
+ m_wanderData.remove(systemIdx);
+}
+
+bool WanderAffector::affectParticle(ParticleData* data, qreal dt)
+{
+ WanderData* d = getData(data->systemIndex);
+ if (m_xVariance != 0.) {
+ if ((d->x_vel > d->x_peak && d->x_var > 0.0) || (d->x_vel < -d->x_peak && d->x_var < 0.0)) {
+ d->x_var = -d->x_var;
+ d->x_peak = m_xVariance + m_xVariance * qreal(qrand()) / RAND_MAX;
+ }
+ d->x_vel += d->x_var * dt;
+ }
+ qreal dx = dt * d->x_vel;
+
+ if (m_yVariance != 0.) {
+ if ((d->y_vel > d->y_peak && d->y_var > 0.0) || (d->y_vel < -d->y_peak && d->y_var < 0.0)) {
+ d->y_var = -d->y_var;
+ d->y_peak = m_yVariance + m_yVariance * qreal(qrand()) / RAND_MAX;
+ }
+ d->y_vel += d->y_var * dt;
+ }
+ qreal dy = dt * d->x_vel;
+
+ //### Should we be amending vel instead?
+ ParticleVertex* p = &(data->pv);
+ p->x += dx;
+
+ p->y += dy;
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/wanderaffector.h b/src/imports/particles/wanderaffector.h
new file mode 100644
index 0000000000..612872830b
--- /dev/null
+++ b/src/imports/particles/wanderaffector.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WANDERAFFECTOR_H
+#define WANDERAFFECTOR_H
+#include <QHash>
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class SpriteEmitter;
+
+struct WanderData{
+ qreal x_vel;
+ qreal y_vel;
+ qreal x_peak;
+ qreal x_var;
+ qreal y_peak;
+ qreal y_var;
+};
+
+class WanderAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal xVariance READ xVariance WRITE setXVariance NOTIFY xVarianceChanged)
+ Q_PROPERTY(qreal yVariance READ yVariance WRITE setYVariance NOTIFY yVarianceChanged)
+ Q_PROPERTY(qreal pace READ pace WRITE setPace NOTIFY paceChanged)
+
+public:
+ explicit WanderAffector(QSGItem *parent = 0);
+ ~WanderAffector();
+ virtual void reset(int systemIdx);
+
+ qreal xVariance() const
+ {
+ return m_xVariance;
+ }
+
+ qreal yVariance() const
+ {
+ return m_yVariance;
+ }
+
+ qreal pace() const
+ {
+ return m_pace;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void xVarianceChanged(qreal arg);
+
+ void yVarianceChanged(qreal arg);
+
+ void paceChanged(qreal arg);
+
+public slots:
+void setXVariance(qreal arg)
+{
+ if (m_xVariance != arg) {
+ m_xVariance = arg;
+ emit xVarianceChanged(arg);
+ }
+}
+
+void setYVariance(qreal arg)
+{
+ if (m_yVariance != arg) {
+ m_yVariance = arg;
+ emit yVarianceChanged(arg);
+ }
+}
+
+void setPace(qreal arg)
+{
+ if (m_pace != arg) {
+ m_pace = arg;
+ emit paceChanged(arg);
+ }
+}
+
+private:
+ WanderData* getData(int idx);
+ QHash<int, WanderData*> m_wanderData;
+ qreal m_xVariance;
+ qreal m_yVariance;
+ qreal m_pace;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // WANDERAFFECTOR_H
diff --git a/src/imports/particles/zoneaffector.cpp b/src/imports/particles/zoneaffector.cpp
new file mode 100644
index 0000000000..cb7adca795
--- /dev/null
+++ b/src/imports/particles/zoneaffector.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "zoneaffector.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+ZoneAffector::ZoneAffector(QObject *parent) :
+ ParticleAffector(parent), m_x(0), m_y(0), m_width(0), m_height(0), m_affector(0)
+{
+}
+
+bool ZoneAffector::affect(ParticleData *d, qreal dt)
+{
+ if(!m_affector)
+ return false;
+ qreal x = d->curX();
+ qreal y = d->curY();
+ if(x >= m_x && x <= m_x+m_width && y >= m_y && y <= m_y+m_height)
+ return m_affector->affect(d, dt);
+ return false;
+}
+
+void ZoneAffector::reset(int systemIdx)
+{
+ if(m_affector)
+ m_affector->reset(systemIdx);
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/zoneaffector.h b/src/imports/particles/zoneaffector.h
new file mode 100644
index 0000000000..8c17cedba2
--- /dev/null
+++ b/src/imports/particles/zoneaffector.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ZONEAFFECTOR_H
+#define ZONEAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ZoneAffector : public ParticleAffector
+{
+ Q_OBJECT
+ //TODO: Can we get anchors in here? consider becoming an un-parented QSGItem?
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged);
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged);
+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged);
+ Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged);
+ Q_PROPERTY(ParticleAffector* affector READ affector WRITE affector NOTIFY affectorChanged)
+ Q_CLASSINFO("DefaultProperty", "affector")
+public:
+ explicit ZoneAffector(QObject *parent = 0);
+
+ virtual bool affect(ParticleData *d, qreal dt);
+ virtual void reset(int systemIdx);
+
+ ParticleAffector* affector() const
+ {
+ return m_affector;
+ }
+
+ qreal x() const
+ {
+ return m_x;
+ }
+
+ qreal y() const
+ {
+ return m_y;
+ }
+
+ qreal width() const
+ {
+ return m_width;
+ }
+
+ qreal height() const
+ {
+ return m_height;
+ }
+
+signals:
+
+
+ void affectorChanged(ParticleAffector* arg);
+
+ void xChanged(qreal arg);
+
+ void yChanged(qreal arg);
+
+ void widthChanged(qreal arg);
+
+ void heightChanged(qreal arg);
+
+public slots:
+
+
+void affector(ParticleAffector* arg)
+{
+ if (m_affector != arg) {
+ m_affector = arg;
+ emit affectorChanged(arg);
+ }
+}
+
+void setX(qreal arg)
+{
+ if (m_x != arg) {
+ m_x = arg;
+ emit xChanged(arg);
+ }
+}
+
+void setY(qreal arg)
+{
+ if (m_y != arg) {
+ m_y = arg;
+ emit yChanged(arg);
+ }
+}
+
+void setWidth(qreal arg)
+{
+ if (m_width != arg) {
+ m_width = arg;
+ emit widthChanged(arg);
+ }
+}
+
+void setHeight(qreal arg)
+{
+ if (m_height != arg) {
+ m_height = arg;
+ emit heightChanged(arg);
+ }
+}
+
+private:
+qreal m_x;
+qreal m_y;
+qreal m_width;
+qreal m_height;
+ParticleAffector* m_affector;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ZONEAFFECTOR_H
diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
index 85c43e3760..437c4061b1 100644
--- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
+++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
@@ -54,6 +54,7 @@ public:
QTcpServerConnectionPrivate();
int port;
+ bool block;
QTcpSocket *socket;
QPacketProtocol *protocol;
QTcpServer *tcpServer;
@@ -63,6 +64,7 @@ public:
QTcpServerConnectionPrivate::QTcpServerConnectionPrivate() :
port(0),
+ block(false),
socket(0),
protocol(0),
tcpServer(0),
@@ -119,10 +121,17 @@ void QTcpServerConnection::disconnect()
d->socket = 0;
}
+bool QTcpServerConnection::waitForMessage()
+{
+ Q_D(QTcpServerConnection);
+ return d->protocol->waitForReadyRead(-1);
+}
+
void QTcpServerConnection::setPort(int port, bool block)
{
Q_D(QTcpServerConnection);
d->port = port;
+ d->block = block;
listen();
if (block)
@@ -169,8 +178,11 @@ void QTcpServerConnection::newConnection()
d->socket->setParent(this);
d->protocol = new QPacketProtocol(d->socket, this);
QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
-}
+ if (d->block) {
+ d->protocol->waitForReadyRead(-1);
+ }
+}
Q_EXPORT_PLUGIN2(tcpserver, QTcpServerConnection)
diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h
index 66a10e18db..1c972b5dd7 100644
--- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h
+++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h
@@ -67,6 +67,7 @@ public:
bool isConnected() const;
void send(const QByteArray &message);
void disconnect();
+ bool waitForMessage();
void listen();
void waitForConnection();
diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro
index 98e15e8b0e..8db6eb172c 100644
--- a/tests/auto/declarative/declarative.pro
+++ b/tests/auto/declarative/declarative.pro
@@ -26,6 +26,9 @@ SUBDIRS += \
qmlvisual \
moduleqt47
+SUBDIRS += \
+ qsgitem \
+
contains(QT_CONFIG, private_tests) {
SUBDIRS += \
qdeclarativeanchors \
@@ -39,7 +42,6 @@ contains(QT_CONFIG, private_tests) {
qdeclarativedebug \
qdeclarativedebugclient \
qdeclarativedebugservice \
- qdeclarativedom \
qdeclarativeecmascript \
qdeclarativeflickable \
qdeclarativeflipable \
@@ -75,7 +77,25 @@ contains(QT_CONFIG, private_tests) {
qdeclarativevisualdatamodel \
qdeclarativeworkerscript \
qdeclarativexmllistmodel \
- qpacketprotocol
+ qpacketprotocol \
+ qdeclarativev4 \
+ qsgcanvas \
+ qsgflickable \
+ qsgflipable \
+ qsgfocusscope \
+ qsggridview \
+ qsglistview \
+ qsgloader \
+ qsgmousearea \
+ qsgpathview \
+ qsgpincharea \
+ qsgpositioners \
+ qsgrepeater \
+ qsgtext \
+ qsgtextedit \
+ qsgtextinput \
+ qsgvisualdatamodel
+
}
# Tests which should run in Pulse
diff --git a/tests/auto/declarative/examples/tst_examples.cpp b/tests/auto/declarative/examples/tst_examples.cpp
index 1a5ff107a4..72d1ff639a 100644
--- a/tests/auto/declarative/examples/tst_examples.cpp
+++ b/tests/auto/declarative/examples/tst_examples.cpp
@@ -45,6 +45,7 @@
#include <QDebug>
#include "qmlruntime.h"
#include <QDeclarativeView>
+#include <QSGView>
#include <QDeclarativeError>
#ifdef Q_OS_SYMBIAN
@@ -61,10 +62,11 @@ public:
private slots:
void examples_data();
void examples();
+ void sgexamples_data();
+ void sgexamples();
void namingConvention();
private:
- QString qmlruntime;
QStringList excludedDirs;
void namingConvention(const QDir &);
@@ -73,24 +75,15 @@ private:
tst_examples::tst_examples()
{
- QString binaries = QLibraryInfo::location(QLibraryInfo::BinariesPath);
-
-#if defined(Q_WS_MAC)
- qmlruntime = QDir(binaries).absoluteFilePath("qml.app/Contents/MacOS/qml");
-#elif defined(Q_WS_WIN)
- qmlruntime = QDir(binaries).absoluteFilePath("qml.exe");
-#else
- qmlruntime = QDir(binaries).absoluteFilePath("qml");
-#endif
-
-
// Add directories you want excluded here
excludedDirs << "doc/src/snippets/declarative/visualdatamodel_rootindex";
excludedDirs << "doc/src/snippets/declarative/qtbinding";
+ excludedDirs << "doc/src/snippets/declarative/imports";
#ifdef QT_NO_WEBKIT
excludedDirs << "examples/declarative/modelviews/webview";
excludedDirs << "demos/declarative/webbrowser";
+ excludedDirs << "doc/src/snippets/declarative/webview";
#endif
#ifdef QT_NO_XMLPATTERNS
@@ -225,6 +218,31 @@ void tst_examples::examples()
QTest::qWaitForWindowShown(&viewer);
}
+void tst_examples::sgexamples_data()
+{
+ examples_data();
+}
+
+void tst_examples::sgexamples()
+{
+ qputenv("QMLSCENE_IMPORT_NAME", "quick1");
+ QFETCH(QString, file);
+
+ QSGView view;
+
+ QtMsgHandler old = qInstallMsgHandler(silentErrorsMsgHandler);
+ view.setSource(file);
+ qInstallMsgHandler(old);
+
+ if (view.status() == QSGView::Error)
+ qWarning() << view.errors();
+
+ QCOMPARE(view.status(), QSGView::Ready);
+ view.show();
+
+ QTest::qWaitForWindowShown(&view);
+}
+
QTEST_MAIN(tst_examples)
#include "tst_examples.moc"
diff --git a/tests/auto/declarative/geometry/geometry.pro b/tests/auto/declarative/geometry/geometry.pro
new file mode 100644
index 0000000000..93b9bdb8ae
--- /dev/null
+++ b/tests/auto/declarative/geometry/geometry.pro
@@ -0,0 +1,10 @@
+load(qttest_p4)
+QT += opengl declarative
+
+TARGET = tst_geometry
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_geometry.cpp
+
+CONFIG+=parallel_test
+
diff --git a/tests/auto/declarative/geometry/tst_geometry.cpp b/tests/auto/declarative/geometry/tst_geometry.cpp
new file mode 100644
index 0000000000..4df7800cb9
--- /dev/null
+++ b/tests/auto/declarative/geometry/tst_geometry.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt scene graph research project.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QString>
+#include <QtTest/QtTest>
+
+#include <qsggeometry.h>
+
+class GeometryTest : public QObject
+{
+ Q_OBJECT
+
+public:
+
+private Q_SLOTS:
+ void testPoint2D();
+ void testTexturedPoint2D();
+ void testCustomGeometry();
+
+private:
+};
+
+void GeometryTest::testPoint2D()
+{
+ QSGGeometry geometry(QSGGeometry::defaultAttributes_Point2D(), 4, 0);
+
+ QCOMPARE(geometry.attributeCount(), 1);
+ QCOMPARE(geometry.stride(), (int) sizeof(float) * 2);
+ QCOMPARE(geometry.vertexCount(), 4);
+ QCOMPARE(geometry.indexCount(), 0);
+ QVERIFY(geometry.indexData() == 0);
+
+ QSGGeometry::updateRectGeometry(&geometry, QRectF(1, 2, 3, 4));
+
+ QSGGeometry::Point2D *pts = geometry.vertexDataAsPoint2D();
+ QVERIFY(pts != 0);
+
+ QCOMPARE(pts[0].x, (float) 1);
+ QCOMPARE(pts[0].y, (float) 2);
+ QCOMPARE(pts[3].x, (float) 4);
+ QCOMPARE(pts[3].y, (float) 6);
+
+ // Verify that resize gives me enough allocated data without crashing...
+ geometry.allocate(100, 100);
+ pts = geometry.vertexDataAsPoint2D();
+ quint16 *is = geometry.indexDataAsUShort();
+ for (int i=0; i<100; ++i) {
+ pts[i].x = i;
+ pts[i].y = i + 100;
+ is[i] = i;
+ }
+ QVERIFY(true);
+}
+
+
+void GeometryTest::testTexturedPoint2D()
+{
+ QSGGeometry geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4, 0);
+
+ QCOMPARE(geometry.attributeCount(), 2);
+ QCOMPARE(geometry.stride(), (int) sizeof(float) * 4);
+ QCOMPARE(geometry.vertexCount(), 4);
+ QCOMPARE(geometry.indexCount(), 0);
+ QVERIFY(geometry.indexData() == 0);
+
+ QSGGeometry::updateTexturedRectGeometry(&geometry, QRectF(1, 2, 3, 4), QRectF(5, 6, 7, 8));
+
+ QSGGeometry::TexturedPoint2D *pts = geometry.vertexDataAsTexturedPoint2D();
+ QVERIFY(pts != 0);
+
+ QCOMPARE(pts[0].x, (float) 1);
+ QCOMPARE(pts[0].y, (float) 2);
+ QCOMPARE(pts[0].tx, (float) 5);
+ QCOMPARE(pts[0].ty, (float) 6);
+
+ QCOMPARE(pts[3].x, (float) 4);
+ QCOMPARE(pts[3].y, (float) 6);
+ QCOMPARE(pts[3].tx, (float) 12);
+ QCOMPARE(pts[3].ty, (float) 14);
+
+ // Verify that resize gives me enough allocated data without crashing...
+ geometry.allocate(100, 100);
+ pts = geometry.vertexDataAsTexturedPoint2D();
+ quint16 *is = geometry.indexDataAsUShort();
+ for (int i=0; i<100; ++i) {
+ pts[i].x = i;
+ pts[i].y = i + 100;
+ pts[i].tx = i + 200;
+ pts[i].ty = i + 300;
+ is[i] = i;
+ }
+ QVERIFY(true);
+}
+
+void GeometryTest::testCustomGeometry()
+{
+ struct V {
+ float x, y;
+ unsigned char r, g, b, a;
+ float v1, v2, v3, v4;
+ };
+
+ static QSGGeometry::Attribute attributes[] = {
+ { 0, 2, GL_FLOAT },
+ { 1, 4, GL_UNSIGNED_BYTE },
+ { 2, 4, GL_FLOAT },
+ };
+ static QSGGeometry::AttributeSet set = { 4, 6 * sizeof(float) + 4 * sizeof(unsigned char), attributes };
+
+ QSGGeometry geometry(set, 1000, 4000);
+
+ // Verify that space has been allocated.
+ quint16 *ii = geometry.indexDataAsUShort();
+ for (int i=0; i<geometry.indexCount(); ++i) {
+ ii[i] = i;
+ }
+
+ V *v = (V *) geometry.vertexData();
+ for (int i=0; i<geometry.vertexCount(); ++i) {
+ v[i].x = 0;
+ v[i].y = 1;
+ v[i].r = 2;
+ v[i].g = 3;
+ v[i].b = 4;
+ v[i].a = 5;
+ v[i].v1 = 6;
+ v[i].v2 = 7;
+ v[i].v3 = 8;
+ v[i].v4 = 9;
+ }
+
+ // Verify the data's integrity
+ for (int i=0; i<4000; ++i)
+ QCOMPARE(ii[i], (quint16) i);
+ for (int i=0; i<1000; ++i)
+ QVERIFY(v[i].v1 == 6);
+
+}
+
+
+QTEST_MAIN(GeometryTest);
+
+#include "tst_geometry.moc"
diff --git a/tests/auto/declarative/node/nodes.pro b/tests/auto/declarative/node/nodes.pro
new file mode 100644
index 0000000000..4d2c06f495
--- /dev/null
+++ b/tests/auto/declarative/node/nodes.pro
@@ -0,0 +1,10 @@
+load(qttest_p4)
+QT += opengl declarative
+
+TARGET = tst_nodestest
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_nodestest.cpp
+
+CONFIG+=parallel_test
+
diff --git a/tests/auto/declarative/node/tst_nodestest.cpp b/tests/auto/declarative/node/tst_nodestest.cpp
new file mode 100644
index 0000000000..a1b0a6ac91
--- /dev/null
+++ b/tests/auto/declarative/node/tst_nodestest.cpp
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt scene graph research project.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QString>
+#include <QtTest/QtTest>
+
+#include <qsgnode.h>
+#include <private/qsgrenderer_p.h>
+#include <private/qsgnodeupdater_p.h>
+
+#include <qsgsimplerectnode.h>
+
+class NodesTest : public QObject
+{
+ Q_OBJECT
+
+public:
+ NodesTest();
+
+private Q_SLOTS:
+ void initTestCase();
+ void cleanupTestCase() {
+ delete widget;
+ }
+
+ // Root nodes
+ void propegate();
+ void propegateWithMultipleRoots();
+ void simulatedEffect_data();
+ void simulatedEffect();
+
+ // Opacity nodes
+ void basicOpacityNode();
+ void opacityPropegation();
+
+ // QSGNodeUpdater
+ void isBlockedCheck();
+
+private:
+ QGLWidget *widget;
+
+ QSGNodeUpdater updater;
+};
+
+void NodesTest::initTestCase()
+{
+ widget = new QGLWidget();
+ widget->resize(100, 30);
+ widget->show();
+}
+
+class DummyRenderer : public QSGRenderer
+{
+public:
+ DummyRenderer(QSGRootNode *root)
+ : QSGRenderer(QSGContext::createDefaultContext())
+ , changedNode(0)
+ , changedFlags(0)
+ , renderCount(0)
+ {
+ setRootNode(root);
+ }
+
+ void render() {
+ ++renderCount;
+ renderingOrder = ++globalRendereringOrder;
+ }
+
+ void nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags) {
+ changedNode = node;
+ changedFlags = flags;
+ QSGRenderer::nodeChanged(node, flags);
+ }
+
+ QSGNode *changedNode;
+ QSGNode::DirtyFlags changedFlags;
+
+ int renderCount;
+ int renderingOrder;
+ static int globalRendereringOrder;
+};
+
+int DummyRenderer::globalRendereringOrder;
+
+NodesTest::NodesTest()
+{
+}
+
+
+void NodesTest::propegate()
+{
+ QSGRootNode root;
+ QSGNode child; child.setFlag(QSGNode::OwnedByParent, false);
+ root.appendChildNode(&child);
+
+ DummyRenderer renderer(&root);
+
+ child.markDirty(QSGNode::DirtyGeometry);
+
+ QCOMPARE(&child, renderer.changedNode);
+ QCOMPARE((int) renderer.changedFlags, (int) QSGNode::DirtyGeometry);
+}
+
+
+void NodesTest::propegateWithMultipleRoots()
+{
+ QSGRootNode root1;
+ QSGNode child2; child2.setFlag(QSGNode::OwnedByParent, false);
+ QSGRootNode root3; root3.setFlag(QSGNode::OwnedByParent, false);
+ QSGNode child4; child4.setFlag(QSGNode::OwnedByParent, false);
+
+ root1.appendChildNode(&child2);
+ child2.appendChildNode(&root3);
+ root3.appendChildNode(&child4);
+
+ DummyRenderer ren1(&root1);
+ DummyRenderer ren2(&root3);
+
+ child4.markDirty(QSGNode::DirtyGeometry);
+
+ QCOMPARE(ren1.changedNode, &child4);
+ QCOMPARE(ren2.changedNode, &child4);
+
+ QCOMPARE((int) ren1.changedFlags, (int) QSGNode::DirtyGeometry);
+ QCOMPARE((int) ren2.changedFlags, (int) QSGNode::DirtyGeometry);
+}
+
+
+
+class SimulatedEffectRenderer : public DummyRenderer
+{
+public:
+ SimulatedEffectRenderer(QSGRootNode *root, QSGBasicGeometryNode *c)
+ : DummyRenderer(root)
+ {
+ child = c;
+ }
+
+ void render() {
+ matrix = child->matrix() ? *child->matrix() : QMatrix4x4();
+ DummyRenderer::render();
+ }
+
+ QSGBasicGeometryNode *child;
+ QMatrix4x4 matrix;
+};
+
+
+class PseudoEffectNode : public QSGNode {
+public:
+ PseudoEffectNode(QSGRenderer *r)
+ : renderer(r)
+ {
+ setFlag(UsePreprocess);
+ }
+
+ void preprocess() {
+
+ if (renderer->rootNode()->parent()) {
+ // Mark the root dirty to build a clean state from the root and down
+ renderer->rootNode()->markDirty(QSGNode::DirtyAll);
+ }
+
+ renderer->renderScene();
+
+ if (renderer->rootNode()->parent()) {
+ // Mark the parent of the root dirty to force the root and down to be updated.
+ renderer->rootNode()->parent()->markDirty(QSGNode::DirtyAll);
+ }
+ }
+
+ QSGRenderer *renderer;
+};
+
+void NodesTest::simulatedEffect_data()
+{
+ QTest::addColumn<bool>("connected");
+
+ QTest::newRow("connected") << true;
+ QTest::newRow("disconnected") << false;
+}
+
+void NodesTest::simulatedEffect()
+{
+ QFETCH(bool, connected);
+
+ QSGRootNode root;
+ QSGRootNode source;
+ QSGTransformNode xform;
+ QSGSimpleRectNode geometry;
+ geometry.setRect(QRectF(0, 0, 1, 1));
+ geometry.setColor(Qt::red);
+
+ root.setFlag(QSGNode::OwnedByParent, false);
+ source.setFlag(QSGNode::OwnedByParent, false);
+ xform.setFlag(QSGNode::OwnedByParent, false);
+ geometry.setFlag(QSGNode::OwnedByParent, false);
+
+ SimulatedEffectRenderer rootRenderer(&root, &geometry);
+ SimulatedEffectRenderer sourceRenderer(&source, &geometry);
+
+ PseudoEffectNode effect(&sourceRenderer);
+
+ /*
+ root Source is redirected into effect using the SimulatedEffectRenderer
+ / \
+ xform effect
+ |
+ source
+ |
+ geometry
+ */
+
+ root.appendChildNode(&xform);
+ root.appendChildNode(&effect);
+ if (connected)
+ xform.appendChildNode(&source);
+ source.appendChildNode(&geometry);
+ QMatrix4x4 m; m.translate(1, 2, 3);
+ xform.setMatrix(m);
+
+ // Clear all dirty states...
+ updater.updateStates(&root);
+
+ rootRenderer.renderScene();
+
+ // compare that we got one render call to each
+ QCOMPARE(rootRenderer.renderCount, 1);
+ QCOMPARE(sourceRenderer.renderCount, 1);
+ QVERIFY(sourceRenderer.renderingOrder < rootRenderer.renderingOrder);
+ if (connected) // geometry is not rendered in this case, so skip it...
+ QCOMPARE(rootRenderer.matrix, xform.matrix());
+ QCOMPARE(sourceRenderer.matrix, QMatrix4x4());
+}
+
+void NodesTest::basicOpacityNode()
+{
+ QSGOpacityNode n;
+ QCOMPARE(n.opacity(), 1.);
+
+ n.setOpacity(0.5);
+ QCOMPARE(n.opacity(), 0.5);
+
+ n.setOpacity(-1);
+ QCOMPARE(n.opacity(), 0.);
+
+ n.setOpacity(2);
+ QCOMPARE(n.opacity(), 1.);
+}
+
+void NodesTest::opacityPropegation()
+{
+ QSGRootNode root;
+ QSGOpacityNode *a = new QSGOpacityNode;
+ QSGOpacityNode *b = new QSGOpacityNode;
+ QSGOpacityNode *c = new QSGOpacityNode;
+
+ QSGSimpleRectNode *geometry = new QSGSimpleRectNode;
+ geometry->setRect(0, 0, 100, 100);
+
+ root.appendChildNode(a);
+ a->appendChildNode(b);
+ b->appendChildNode(c);
+ c->appendChildNode(geometry);
+
+ a->setOpacity(0.9);
+ b->setOpacity(0.8);
+ c->setOpacity(0.7);
+
+ updater.updateStates(&root);
+
+ QCOMPARE(a->combinedOpacity(), 0.9);
+ QCOMPARE(b->combinedOpacity(), 0.9 * 0.8);
+ QCOMPARE(c->combinedOpacity(), 0.9 * 0.8 * 0.7);
+ QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.8 * 0.7);
+
+ b->setOpacity(0.1);
+ updater.updateStates(&root);
+
+ QCOMPARE(a->combinedOpacity(), 0.9);
+ QCOMPARE(b->combinedOpacity(), 0.9 * 0.1);
+ QCOMPARE(c->combinedOpacity(), 0.9 * 0.1 * 0.7);
+ QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.1 * 0.7);
+
+ b->setOpacity(0);
+ updater.updateStates(&root);
+
+ QVERIFY(b->isSubtreeBlocked());
+
+ // Verify that geometry did not get updated as it is in a blocked
+ // subtree
+ QCOMPARE(c->combinedOpacity(), 0.9 * 0.1 * 0.7);
+ QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.1 * 0.7);
+}
+
+void NodesTest::isBlockedCheck()
+{
+ QSGRootNode root;
+ QSGOpacityNode *opacity = new QSGOpacityNode();
+ QSGNode *node = new QSGNode();
+
+ root.appendChildNode(opacity);
+ opacity->appendChildNode(node);
+
+ QSGNodeUpdater updater;
+
+ opacity->setOpacity(0);
+ QVERIFY(updater.isNodeBlocked(node, &root));
+
+ opacity->setOpacity(1);
+ QVERIFY(!updater.isNodeBlocked(node, &root));
+}
+
+QTEST_MAIN(NodesTest);
+
+#include "tst_nodestest.moc"
diff --git a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp
index de4ddcc360..e63b14ef61 100644
--- a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp
+++ b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp
@@ -664,7 +664,13 @@ void tst_QDeclarativeDebug::queryAvailableEngines()
QCOMPARE(e.name(), m_engine->objectName());
}
+ // Make query invalid by deleting client
+ q_engines = m_dbg->queryAvailableEngines(this);
+ QCOMPARE(q_engines->state(), QDeclarativeDebugQuery::Waiting);
+ delete m_dbg;
+ QCOMPARE(q_engines->state(), QDeclarativeDebugQuery::Error);
delete q_engines;
+ m_dbg = new QDeclarativeEngineDebug(m_conn, this);
}
void tst_QDeclarativeDebug::queryRootContexts()
@@ -672,6 +678,7 @@ void tst_QDeclarativeDebug::queryRootContexts()
QDeclarativeDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this);
waitForQuery(q_engines);
int engineId = q_engines->engines()[0].debugId();
+ delete q_engines;
QDeclarativeDebugRootContextQuery *q_context;
@@ -703,8 +710,13 @@ void tst_QDeclarativeDebug::queryRootContexts()
QVERIFY(context.contexts()[0].debugId() >= 0);
QCOMPARE(context.contexts()[0].name(), QString("tst_QDeclarativeDebug_childContext"));
- delete q_engines;
+ // Make query invalid by deleting client
+ q_context = m_dbg->queryRootContexts(engineId, this);
+ QCOMPARE(q_context->state(), QDeclarativeDebugQuery::Waiting);
+ delete m_dbg;
+ QCOMPARE(q_context->state(), QDeclarativeDebugQuery::Error);
delete q_context;
+ m_dbg = new QDeclarativeEngineDebug(m_conn, this);
}
void tst_QDeclarativeDebug::queryObject()
@@ -736,7 +748,14 @@ void tst_QDeclarativeDebug::queryObject()
delete q_engines;
delete q_context;
+
+ // Make query invalid by deleting client
+ q_obj = recursive ? m_dbg->queryObjectRecursive(rootObject, this) : m_dbg->queryObject(rootObject, this);
+ QCOMPARE(q_obj->state(), QDeclarativeDebugQuery::Waiting);
+ delete m_dbg;
+ QCOMPARE(q_obj->state(), QDeclarativeDebugQuery::Error);
delete q_obj;
+ m_dbg = new QDeclarativeEngineDebug(m_conn, this);
// check source as defined in main()
QDeclarativeDebugFileReference source = obj.source();
@@ -811,7 +830,14 @@ void tst_QDeclarativeDebug::queryExpressionResult()
delete q_engines;
delete q_context;
+
+ // Make query invalid by deleting client
+ q_expr = m_dbg->queryExpressionResult(objectId, expr, this);
+ QCOMPARE(q_expr->state(), QDeclarativeDebugQuery::Waiting);
+ delete m_dbg;
+ QCOMPARE(q_expr->state(), QDeclarativeDebugQuery::Error);
delete q_expr;
+ m_dbg = new QDeclarativeEngineDebug(m_conn, this);
}
void tst_QDeclarativeDebug::queryExpressionResult_data()
@@ -1001,7 +1027,7 @@ void tst_QDeclarativeDebug::setBindingForObject()
// set handler
//
rootObject = findRootObject();
- QCOMPARE(rootObject.children().size(), 3);
+ QCOMPARE(rootObject.children().size(), 4); // Rectangle, Text, MouseArea, QDeclarativeComponentAttached
QDeclarativeDebugObjectReference mouseAreaObject = rootObject.children().at(2);
QDeclarativeDebugObjectQuery *q_obj = m_dbg->queryObjectRecursive(mouseAreaObject, this);
waitForQuery(q_obj);
diff --git a/tests/auto/declarative/qdeclarativedom/data/MyItem.qml b/tests/auto/declarative/qdeclarativedom/data/MyItem.qml
deleted file mode 100644
index f6760b6a9f..0000000000
--- a/tests/auto/declarative/qdeclarativedom/data/MyItem.qml
+++ /dev/null
@@ -1,4 +0,0 @@
-import QtQuick 1.0
-
-Item {
-}
diff --git a/tests/auto/declarative/qdeclarativedom/data/import/Bar.qml b/tests/auto/declarative/qdeclarativedom/data/import/Bar.qml
deleted file mode 100644
index 86a7176896..0000000000
--- a/tests/auto/declarative/qdeclarativedom/data/import/Bar.qml
+++ /dev/null
@@ -1,2 +0,0 @@
-import QtQuick 1.0
-
diff --git a/tests/auto/declarative/qdeclarativedom/data/importlib/sublib/Foo.qml b/tests/auto/declarative/qdeclarativedom/data/importlib/sublib/Foo.qml
deleted file mode 100644
index 86a7176896..0000000000
--- a/tests/auto/declarative/qdeclarativedom/data/importlib/sublib/Foo.qml
+++ /dev/null
@@ -1,2 +0,0 @@
-import QtQuick 1.0
-
diff --git a/tests/auto/declarative/qdeclarativedom/data/importlib/sublib/qmldir b/tests/auto/declarative/qdeclarativedom/data/importlib/sublib/qmldir
deleted file mode 100644
index 98d6b7431d..0000000000
--- a/tests/auto/declarative/qdeclarativedom/data/importlib/sublib/qmldir
+++ /dev/null
@@ -1,2 +0,0 @@
-Foo 1.1 Foo.qml
-Foo 1.0 Foo.qml
diff --git a/tests/auto/declarative/qdeclarativedom/data/top.qml b/tests/auto/declarative/qdeclarativedom/data/top.qml
deleted file mode 100644
index 56ea9dfaad..0000000000
--- a/tests/auto/declarative/qdeclarativedom/data/top.qml
+++ /dev/null
@@ -1,6 +0,0 @@
-import QtQuick 1.0
-
-MyComponent {
- width: 100
- height: 100
-}
diff --git a/tests/auto/declarative/qdeclarativedom/tst_qdeclarativedom.cpp b/tests/auto/declarative/qdeclarativedom/tst_qdeclarativedom.cpp
deleted file mode 100644
index e62a114b78..0000000000
--- a/tests/auto/declarative/qdeclarativedom/tst_qdeclarativedom.cpp
+++ /dev/null
@@ -1,1326 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include <qtest.h>
-#include <QtDeclarative/qdeclarativeengine.h>
-#include <QtDeclarative/qdeclarativecomponent.h>
-#include <QtDeclarative/private/qdeclarativedom_p.h>
-
-#include <QtCore/QDebug>
-#include <QtCore/QFile>
-
-#ifdef Q_OS_SYMBIAN
-// In Symbian OS test data is located in applications private dir
-#define SRCDIR "."
-#endif
-
-class tst_qdeclarativedom : public QObject
-{
- Q_OBJECT
-public:
- tst_qdeclarativedom() {}
-
-private slots:
- void loadSimple();
- void loadProperties();
- void loadGroupedProperties();
- void loadChildObject();
- void loadComposite();
- void loadImports();
- void loadErrors();
- void loadSyntaxErrors();
- void loadRemoteErrors();
- void loadDynamicProperty();
- void loadComponent();
-
- void testValueSource();
- void testValueInterceptor();
-
- void object_dynamicProperty();
- void object_property();
- void object_url();
-
- void copy();
- void position();
-private:
- QDeclarativeEngine engine;
-};
-
-
-void tst_qdeclarativedom::loadSimple()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {}";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
- QVERIFY(document.errors().isEmpty());
-
- QDeclarativeDomObject rootObject = document.rootObject();
- QVERIFY(rootObject.isValid());
- QVERIFY(!rootObject.isComponent());
- QVERIFY(!rootObject.isCustomType());
- QVERIFY(rootObject.objectType() == "QtQuick/Item");
- QVERIFY(rootObject.objectTypeMajorVersion() == 1);
- QVERIFY(rootObject.objectTypeMinorVersion() == 0);
-}
-
-// Test regular properties
-void tst_qdeclarativedom::loadProperties()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "Item { id : item; x : 300; visible : true }";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootObject = document.rootObject();
- QVERIFY(rootObject.isValid());
- QVERIFY(rootObject.objectId() == "item");
- QCOMPARE(rootObject.properties().size(), 3);
-
- QDeclarativeDomProperty xProperty = rootObject.property("x");
- QVERIFY(xProperty.propertyName() == "x");
- QCOMPARE(xProperty.propertyNameParts().count(), 1);
- QVERIFY(xProperty.propertyNameParts().at(0) == "x");
- QCOMPARE(xProperty.position(), 37);
- QCOMPARE(xProperty.length(), 1);
- QVERIFY(xProperty.value().isLiteral());
- QVERIFY(xProperty.value().toLiteral().literal() == "300");
-
- QDeclarativeDomProperty visibleProperty = rootObject.property("visible");
- QVERIFY(visibleProperty.propertyName() == "visible");
- QCOMPARE(visibleProperty.propertyNameParts().count(), 1);
- QVERIFY(visibleProperty.propertyNameParts().at(0) == "visible");
- QCOMPARE(visibleProperty.position(), 46);
- QCOMPARE(visibleProperty.length(), 7);
- QVERIFY(visibleProperty.value().isLiteral());
- QVERIFY(visibleProperty.value().toLiteral().literal() == "true");
-}
-
-// Test grouped properties
-void tst_qdeclarativedom::loadGroupedProperties()
-{
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "Item { anchors.left: parent.left; anchors.right: parent.right }";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootItem = document.rootObject();
- QVERIFY(rootItem.isValid());
- QVERIFY(rootItem.properties().size() == 2);
-
- // Order is not deterministic
- QDeclarativeDomProperty p0 = rootItem.properties().at(0);
- QDeclarativeDomProperty p1 = rootItem.properties().at(1);
- QDeclarativeDomProperty leftProperty;
- QDeclarativeDomProperty rightProperty;
- if (p0.propertyName() == "anchors.left") {
- leftProperty = p0;
- rightProperty = p1;
- } else {
- leftProperty = p1;
- rightProperty = p0;
- }
-
- QVERIFY(leftProperty.propertyName() == "anchors.left");
- QCOMPARE(leftProperty.propertyNameParts().count(), 2);
- QVERIFY(leftProperty.propertyNameParts().at(0) == "anchors");
- QVERIFY(leftProperty.propertyNameParts().at(1) == "left");
- QCOMPARE(leftProperty.position(), 26);
- QCOMPARE(leftProperty.length(), 12);
- QVERIFY(leftProperty.value().isBinding());
- QVERIFY(leftProperty.value().toBinding().binding() == "parent.left");
-
- QVERIFY(rightProperty.propertyName() == "anchors.right");
- QCOMPARE(rightProperty.propertyNameParts().count(), 2);
- QVERIFY(rightProperty.propertyNameParts().at(0) == "anchors");
- QVERIFY(rightProperty.propertyNameParts().at(1) == "right");
- QCOMPARE(rightProperty.position(), 53);
- QCOMPARE(rightProperty.length(), 13);
- QVERIFY(rightProperty.value().isBinding());
- QVERIFY(rightProperty.value().toBinding().binding() == "parent.right");
- }
-
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "Item { \n"
- " anchors {\n"
- " left: parent.left\n"
- " right: parent.right\n"
- " }\n"
- "}";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootItem = document.rootObject();
- QVERIFY(rootItem.isValid());
- QVERIFY(rootItem.properties().size() == 2);
-
- // Order is not deterministic
- QDeclarativeDomProperty p0 = rootItem.properties().at(0);
- QDeclarativeDomProperty p1 = rootItem.properties().at(1);
- QDeclarativeDomProperty leftProperty;
- QDeclarativeDomProperty rightProperty;
- if (p0.propertyName() == "anchors.left") {
- leftProperty = p0;
- rightProperty = p1;
- } else {
- leftProperty = p1;
- rightProperty = p0;
- }
-
- QVERIFY(leftProperty.propertyName() == "anchors.left");
- QCOMPARE(leftProperty.propertyNameParts().count(), 2);
- QVERIFY(leftProperty.propertyNameParts().at(0) == "anchors");
- QVERIFY(leftProperty.propertyNameParts().at(1) == "left");
- QCOMPARE(leftProperty.position(), 49);
- QCOMPARE(leftProperty.length(), 4);
- QVERIFY(leftProperty.value().isBinding());
- QVERIFY(leftProperty.value().toBinding().binding() == "parent.left");
-
- QVERIFY(rightProperty.propertyName() == "anchors.right");
- QCOMPARE(rightProperty.propertyNameParts().count(), 2);
- QVERIFY(rightProperty.propertyNameParts().at(0) == "anchors");
- QVERIFY(rightProperty.propertyNameParts().at(1) == "right");
- QCOMPARE(rightProperty.position(), 75);
- QCOMPARE(rightProperty.length(), 5);
- QVERIFY(rightProperty.value().isBinding());
- QVERIFY(rightProperty.value().toBinding().binding() == "parent.right");
- }
-
-}
-
-void tst_qdeclarativedom::loadChildObject()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "Item { Item {} }";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootItem = document.rootObject();
- QVERIFY(rootItem.isValid());
- QVERIFY(rootItem.properties().size() == 1);
-
- QDeclarativeDomProperty listProperty = rootItem.properties().at(0);
- QVERIFY(listProperty.isDefaultProperty());
- QVERIFY(listProperty.value().isList());
-
- QDeclarativeDomList list = listProperty.value().toList();
- QVERIFY(list.values().size() == 1);
-
- QDeclarativeDomObject childItem = list.values().first().toObject();
- QVERIFY(childItem.isValid());
- QVERIFY(childItem.objectType() == "QtQuick/Item");
-}
-
-void tst_qdeclarativedom::loadComposite()
-{
- QFile file(SRCDIR "/data/top.qml");
- QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, file.readAll(), QUrl::fromLocalFile(file.fileName())));
- QVERIFY(document.errors().isEmpty());
-
- QDeclarativeDomObject rootItem = document.rootObject();
- QVERIFY(rootItem.isValid());
- QCOMPARE(rootItem.objectType(), QByteArray("MyComponent"));
- QCOMPARE(rootItem.properties().size(), 2);
-
- QDeclarativeDomProperty widthProperty = rootItem.property("width");
- QVERIFY(widthProperty.value().isLiteral());
-
- QDeclarativeDomProperty heightProperty = rootItem.property("height");
- QVERIFY(heightProperty.value().isLiteral());
-}
-
-void tst_qdeclarativedom::testValueSource()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "Rectangle { SpringAnimation on height { spring: 1.4; damping: .15; to: Math.min(Math.max(-130, value*2.2 - 130), 133); }}";
-
- QDeclarativeEngine freshEngine;
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&freshEngine, qml));
-
- QDeclarativeDomObject rootItem = document.rootObject();
- QVERIFY(rootItem.isValid());
- QDeclarativeDomProperty heightProperty = rootItem.properties().at(0);
- QVERIFY(heightProperty.propertyName() == "height");
- QVERIFY(heightProperty.value().isValueSource());
-
- const QDeclarativeDomValueValueSource valueSource = heightProperty.value().toValueSource();
- QDeclarativeDomObject valueSourceObject = valueSource.object();
- QVERIFY(valueSourceObject.isValid());
-
- QVERIFY(valueSourceObject.objectType() == "QtQuick/SpringAnimation");
-
- const QDeclarativeDomValue springValue = valueSourceObject.property("spring").value();
- QVERIFY(!springValue.isInvalid());
- QVERIFY(springValue.isLiteral());
- QVERIFY(springValue.toLiteral().literal() == "1.4");
-
- const QDeclarativeDomValue sourceValue = valueSourceObject.property("to").value();
- QVERIFY(!sourceValue.isInvalid());
- QVERIFY(sourceValue.isBinding());
- QVERIFY(sourceValue.toBinding().binding() == "Math.min(Math.max(-130, value*2.2 - 130), 133)");
-}
-
-void tst_qdeclarativedom::testValueInterceptor()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "Rectangle { Behavior on height { NumberAnimation { duration: 100 } } }";
-
- QDeclarativeEngine freshEngine;
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&freshEngine, qml));
-
- QDeclarativeDomObject rootItem = document.rootObject();
- QVERIFY(rootItem.isValid());
- QDeclarativeDomProperty heightProperty = rootItem.properties().at(0);
- QVERIFY(heightProperty.propertyName() == "height");
- QVERIFY(heightProperty.value().isValueInterceptor());
-
- const QDeclarativeDomValueValueInterceptor valueInterceptor = heightProperty.value().toValueInterceptor();
- QDeclarativeDomObject valueInterceptorObject = valueInterceptor.object();
- QVERIFY(valueInterceptorObject.isValid());
-
- QVERIFY(valueInterceptorObject.objectType() == "QtQuick/Behavior");
-
- const QDeclarativeDomValue animationValue = valueInterceptorObject.property("animation").value();
- QVERIFY(!animationValue.isInvalid());
- QVERIFY(animationValue.isObject());
-}
-
-// Test QDeclarativeDomDocument::imports()
-void tst_qdeclarativedom::loadImports()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "import importlib.sublib 1.1\n"
- "import importlib.sublib 1.0 as NewFoo\n"
- "import 'import'\n"
- "import 'import' as X\n"
- "Item {}";
-
- QDeclarativeEngine engine;
- engine.addImportPath(SRCDIR "/data");
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml, QUrl::fromLocalFile(SRCDIR "/data/dummy.qml")));
-
- QCOMPARE(document.imports().size(), 5);
-
- QDeclarativeDomImport import = document.imports().at(0);
- QCOMPARE(import.type(), QDeclarativeDomImport::Library);
- QCOMPARE(import.uri(), QLatin1String("QtQuick"));
- QCOMPARE(import.qualifier(), QString());
- QCOMPARE(import.version(), QLatin1String("1.0"));
-
- import = document.imports().at(1);
- QCOMPARE(import.type(), QDeclarativeDomImport::Library);
- QCOMPARE(import.uri(), QLatin1String("importlib.sublib"));
- QCOMPARE(import.qualifier(), QString());
- QCOMPARE(import.version(), QLatin1String("1.1"));
-
- import = document.imports().at(2);
- QCOMPARE(import.type(), QDeclarativeDomImport::Library);
- QCOMPARE(import.uri(), QLatin1String("importlib.sublib"));
- QCOMPARE(import.qualifier(), QLatin1String("NewFoo"));
- QCOMPARE(import.version(), QLatin1String("1.0"));
-
- import = document.imports().at(3);
- QCOMPARE(import.type(), QDeclarativeDomImport::File);
- QCOMPARE(import.uri(), QLatin1String("import"));
- QCOMPARE(import.qualifier(), QLatin1String(""));
- QCOMPARE(import.version(), QLatin1String(""));
-
- import = document.imports().at(4);
- QCOMPARE(import.type(), QDeclarativeDomImport::File);
- QCOMPARE(import.uri(), QLatin1String("import"));
- QCOMPARE(import.qualifier(), QLatin1String("X"));
- QCOMPARE(import.version(), QLatin1String(""));
-}
-
-// Test loading a file with errors
-void tst_qdeclarativedom::loadErrors()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {\n"
- " foo: 12\n"
- "}";
-
- QDeclarativeDomDocument document;
- QVERIFY(false == document.load(&engine, qml));
-
- QCOMPARE(document.errors().count(), 1);
- QDeclarativeError error = document.errors().first();
-
- QCOMPARE(error.url(), QUrl());
- QCOMPARE(error.line(), 3);
- QCOMPARE(error.column(), 3);
- QCOMPARE(error.description(), QString("Cannot assign to non-existent property \"foo\""));
-}
-
-// Test loading a file with syntax errors
-void tst_qdeclarativedom::loadSyntaxErrors()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "asdf";
-
- QDeclarativeDomDocument document;
- QVERIFY(false == document.load(&engine, qml));
-
- QCOMPARE(document.errors().count(), 1);
- QDeclarativeError error = document.errors().first();
-
- QCOMPARE(error.url(), QUrl());
- QCOMPARE(error.line(), 2);
- QCOMPARE(error.column(), 1);
- QCOMPARE(error.description(), QString("Syntax error"));
-}
-
-// Test attempting to load a file with remote references
-void tst_qdeclarativedom::loadRemoteErrors()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "import \"http://localhost/exampleQmlScript.js\" as Script\n"
- "Item {\n"
- "}";
- QDeclarativeDomDocument document;
- QVERIFY(false == document.load(&engine, qml));
-
- QCOMPARE(document.errors().count(), 1);
- QDeclarativeError error = document.errors().first();
-
- QCOMPARE(error.url(), QUrl());
- QCOMPARE(error.line(), -1);
- QCOMPARE(error.column(), -1);
- QCOMPARE(error.description(), QString("QDeclarativeDomDocument supports local types only"));
-}
-
-// Test dynamic property declarations
-void tst_qdeclarativedom::loadDynamicProperty()
-{
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {\n"
- " property int a\n"
- " property bool b\n"
- " property double c\n"
- " property real d\n"
- " property string e\n"
- " property url f\n"
- " property color g\n"
- " property date h\n"
- " property variant i\n"
- " property QtObject j\n"
- "}";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootObject = document.rootObject();
- QVERIFY(rootObject.isValid());
-
- QCOMPARE(rootObject.dynamicProperties().count(), 10);
-
-#define DP_TEST(index, name, type, test_position, test_length, propTypeName) \
- { \
- QDeclarativeDomDynamicProperty d = rootObject.dynamicProperties().at(index); \
- QVERIFY(d.isValid()); \
- QVERIFY(d.propertyName() == # name ); \
- QVERIFY(d.propertyType() == type); \
- QVERIFY(d.propertyTypeName() == propTypeName); \
- QVERIFY(d.isDefaultProperty() == false); \
- QVERIFY(d.defaultValue().isValid() == false); \
- QCOMPARE(d.position(), test_position); \
- QCOMPARE(d.length(), test_length); \
- } \
-
- DP_TEST(0, a, QVariant::Int, 30, 14, "int");
- DP_TEST(1, b, QVariant::Bool, 49, 15, "bool");
- DP_TEST(2, c, QMetaType::QReal, 69, 17, "double");
- DP_TEST(3, d, QMetaType::QReal, 91, 15, "real");
- DP_TEST(4, e, QVariant::String, 111, 17, "string");
- DP_TEST(5, f, QVariant::Url, 133, 14, "url");
- DP_TEST(6, g, QVariant::Color, 152, 16, "color");
- DP_TEST(7, h, QVariant::DateTime, 173, 15, "date");
- DP_TEST(8, i, qMetaTypeId<QVariant>(), 193, 18, "variant");
- DP_TEST(9, j, -1, 216, 19, "QtObject");
- }
-
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {\n"
- " id: item\n"
- " property int a: 12\n"
- " property int b: a + 6\n"
- " default property QtObject c\n"
- " property alias d: item.a\n"
- "}\n";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootObject = document.rootObject();
- QVERIFY(rootObject.isValid());
-
- QCOMPARE(rootObject.dynamicProperties().count(), 4);
-
- {
- QDeclarativeDomDynamicProperty d = rootObject.dynamicProperties().at(0);
- QVERIFY(d.isDefaultProperty() == false);
- QVERIFY(d.isAlias() == false);
- QVERIFY(d.defaultValue().isValid());
- QVERIFY(d.defaultValue().propertyName() == "a");
- QVERIFY(d.defaultValue().value().isLiteral());
- }
-
- {
- QDeclarativeDomDynamicProperty d = rootObject.dynamicProperties().at(1);
- QVERIFY(d.isDefaultProperty() == false);
- QVERIFY(d.isAlias() == false);
- QVERIFY(d.defaultValue().isValid());
- QVERIFY(d.defaultValue().propertyName() == "b");
- QVERIFY(d.defaultValue().value().isBinding());
- }
-
- {
- QDeclarativeDomDynamicProperty d = rootObject.dynamicProperties().at(2);
- QVERIFY(d.isDefaultProperty() == true);
- QVERIFY(d.isAlias() == false);
- QVERIFY(d.defaultValue().isValid() == false);
- }
-
- {
- QDeclarativeDomDynamicProperty d = rootObject.dynamicProperties().at(3);
- QVERIFY(d.isDefaultProperty() == false);
- QVERIFY(d.isAlias() == true);
- }
- }
-}
-
-// Test inline components
-void tst_qdeclarativedom::loadComponent()
-{
- // Explicit component
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {\n"
- " Component {\n"
- " id: myComponent\n"
- " Item {}\n"
- " }\n"
- "}";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootItem = document.rootObject();
- QVERIFY(rootItem.isValid());
- QVERIFY(rootItem.properties().size() == 1);
-
- QDeclarativeDomProperty listProperty = rootItem.properties().at(0);
- QVERIFY(listProperty.isDefaultProperty());
- QVERIFY(listProperty.value().isList());
-
- QDeclarativeDomList list = listProperty.value().toList();
- QVERIFY(list.values().size() == 1);
-
- QDeclarativeDomObject componentObject = list.values().first().toObject();
- QVERIFY(componentObject.isValid());
- QVERIFY(componentObject.objectClassName() == "Component");
- QVERIFY(componentObject.isComponent());
-
- QDeclarativeDomComponent component = componentObject.toComponent();
- QVERIFY(component.isValid());
- QVERIFY(component.objectType() == "QtQuick/Component");
- QVERIFY(component.objectTypeMajorVersion() == 1);
- QVERIFY(component.objectTypeMinorVersion() == 0);
- QVERIFY(component.objectClassName() == "Component");
- QVERIFY(component.objectId() == "myComponent");
- QVERIFY(component.properties().isEmpty());
- QVERIFY(component.dynamicProperties().isEmpty());
- QVERIFY(component.isCustomType() == false);
- QVERIFY(component.customTypeData() == "");
- QVERIFY(component.isComponent());
- QCOMPARE(component.position(), 30);
- QCOMPARE(component.length(), 57);
-
- QVERIFY(component.componentRoot().isValid());
- QVERIFY(component.componentRoot().objectClassName() == "Item");
- }
-
- // Implicit component
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "ListView {\n"
- " delegate: Item {}\n"
- "}";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootItem = document.rootObject();
- QVERIFY(rootItem.isValid());
- QVERIFY(rootItem.properties().size() == 1);
-
- QDeclarativeDomProperty delegate = rootItem.property("delegate");
-
- QDeclarativeDomObject componentObject = delegate.value().toObject();
- QVERIFY(componentObject.isValid());
- QVERIFY(componentObject.objectClassName() == "Component");
- QVERIFY(componentObject.isComponent());
-
- QDeclarativeDomComponent component = componentObject.toComponent();
- QVERIFY(component.isValid());
- QVERIFY(component.objectType() == "QtQuick/Component");
- QVERIFY(component.objectClassName() == "Component");
- QVERIFY(component.objectId() == "");
- QVERIFY(component.properties().isEmpty());
- QVERIFY(component.dynamicProperties().isEmpty());
- QVERIFY(component.isCustomType() == false);
- QVERIFY(component.customTypeData() == "");
- QVERIFY(component.isComponent());
- QCOMPARE(component.position(), 44);
- QCOMPARE(component.length(), 7);
-
- QVERIFY(component.componentRoot().isValid());
- QVERIFY(component.componentRoot().objectClassName() == "Item");
- }
-}
-
-// Test QDeclarativeDomObject::dynamicProperty() method
-void tst_qdeclarativedom::object_dynamicProperty()
-{
- // Invalid object
- {
- QDeclarativeDomObject object;
- QVERIFY(object.dynamicProperty("").isValid() == false);
- QVERIFY(object.dynamicProperty("foo").isValid() == false);
- }
-
-
- // Valid object, no dynamic properties
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {}";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootObject = document.rootObject();
- QVERIFY(rootObject.isValid());
-
- QVERIFY(rootObject.dynamicProperty("").isValid() == false);
- QVERIFY(rootObject.dynamicProperty("foo").isValid() == false);
- }
-
- // Valid object, dynamic properties
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {\n"
- " property int a\n"
- "}";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootObject = document.rootObject();
- QVERIFY(rootObject.isValid());
-
- QVERIFY(rootObject.dynamicProperty("").isValid() == false);
- QVERIFY(rootObject.dynamicProperty("foo").isValid() == false);
-
- QDeclarativeDomDynamicProperty p = rootObject.dynamicProperty("a");
- QVERIFY(p.isValid());
- QVERIFY(p.propertyName() == "a");
- QVERIFY(p.propertyType() == QVariant::Int);
- QVERIFY(p.propertyTypeName() == "int");
- QVERIFY(p.isDefaultProperty() == false);
- QCOMPARE(p.position(), 30);
- QCOMPARE(p.length(), 14);
- }
-
-}
-
-// Test QDeclarativeObject::property() method
-void tst_qdeclarativedom::object_property()
-{
- // Invalid object
- {
- QDeclarativeDomObject object;
- QVERIFY(object.property("").isValid() == false);
- QVERIFY(object.property("foo").isValid() == false);
- }
-
- // Valid object - no default
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {\n"
- " x: 10\n"
- " y: 12\n"
- "}\n";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootObject = document.rootObject();
- QVERIFY(rootObject.isValid());
-
- QVERIFY(rootObject.property("").isValid() == false);
- QVERIFY(rootObject.property("foo").isValid() == false);
-
- QDeclarativeDomProperty x = rootObject.property("x");
- QVERIFY(x.isValid());
- QVERIFY(x.propertyName() == "x");
- QVERIFY(x.propertyNameParts().count() == 1);
- QVERIFY(x.propertyNameParts().at(0) == "x");
- QVERIFY(x.isDefaultProperty() == false);
- QVERIFY(x.value().isLiteral());
- QVERIFY(x.value().toLiteral().literal() == "10");
- QCOMPARE(x.position(), 30);
- QCOMPARE(x.length(), 1);
-
- QDeclarativeDomProperty y = rootObject.property("y");
- QVERIFY(y.isValid());
- QVERIFY(y.propertyName() == "y");
- QVERIFY(y.propertyNameParts().count() == 1);
- QVERIFY(y.propertyNameParts().at(0) == "y");
- QVERIFY(y.isDefaultProperty() == false);
- QVERIFY(y.value().isLiteral());
- QVERIFY(y.value().toLiteral().literal() == "12");
- QCOMPARE(y.position(), 40);
- QCOMPARE(y.length(), 1);
- }
-
- // Valid object - with default
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {\n"
- " x: 10\n"
- " y: 12\n"
- " Item {}\n"
- "}\n";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootObject = document.rootObject();
- QVERIFY(rootObject.isValid());
-
- QVERIFY(rootObject.property("").isValid() == false);
- QVERIFY(rootObject.property("foo").isValid() == false);
-
- QDeclarativeDomProperty x = rootObject.property("x");
- QVERIFY(x.isValid());
- QVERIFY(x.propertyName() == "x");
- QVERIFY(x.propertyNameParts().count() == 1);
- QVERIFY(x.propertyNameParts().at(0) == "x");
- QVERIFY(x.isDefaultProperty() == false);
- QVERIFY(x.value().isLiteral());
- QVERIFY(x.value().toLiteral().literal() == "10");
- QCOMPARE(x.position(), 30);
- QCOMPARE(x.length(), 1);
-
- QDeclarativeDomProperty y = rootObject.property("y");
- QVERIFY(y.isValid());
- QVERIFY(y.propertyName() == "y");
- QVERIFY(y.propertyNameParts().count() == 1);
- QVERIFY(y.propertyNameParts().at(0) == "y");
- QVERIFY(y.isDefaultProperty() == false);
- QVERIFY(y.value().isLiteral());
- QVERIFY(y.value().toLiteral().literal() == "12");
- QCOMPARE(y.position(), 40);
- QCOMPARE(y.length(), 1);
-
- QDeclarativeDomProperty data = rootObject.property("data");
- QVERIFY(data.isValid());
- QVERIFY(data.propertyName() == "data");
- QVERIFY(data.propertyNameParts().count() == 1);
- QVERIFY(data.propertyNameParts().at(0) == "data");
- QVERIFY(data.isDefaultProperty() == true);
- QVERIFY(data.value().isList());
- QCOMPARE(data.position(), 50);
- QCOMPARE(data.length(), 0);
- }
-}
-
-// Tests the QDeclarativeDomObject::url() method
-void tst_qdeclarativedom::object_url()
-{
- // Invalid object
- {
- QDeclarativeDomObject object;
- QCOMPARE(object.url(), QUrl());
- }
-
- // Valid builtin object
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {}";
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject rootObject = document.rootObject();
- QVERIFY(rootObject.isValid());
- QCOMPARE(rootObject.url(), QUrl());
- }
-
- // Valid composite object
- {
- QByteArray qml = "import QtQuick 1.0\n"
- "MyItem {}";
-
- QUrl myUrl = QUrl::fromLocalFile(SRCDIR "/data/main.qml");
- QUrl subUrl = QUrl::fromLocalFile(SRCDIR "/data/MyItem.qml");
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml, myUrl));
-
- QDeclarativeDomObject rootObject = document.rootObject();
- QVERIFY(rootObject.isValid());
- QCOMPARE(rootObject.url(), subUrl);
- }
-}
-
-// Test copy constructors and operators
-void tst_qdeclarativedom::copy()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "MyItem {\n"
- " id: myItem\n"
- " property int a: 10\n"
- " x: 10\n"
- " y: x + 10\n"
- " NumberAnimation on z {}\n"
- " Behavior on opacity {}\n"
- " Component {\n"
- " Item{}\n"
- " }\n"
- " children: [ Item{}, Item{} ]\n"
- "}\n";
-
- QUrl myUrl = QUrl::fromLocalFile(SRCDIR "/data/main.qml");
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml, myUrl));
-
- // QDeclarativeDomDocument
- {
- QDeclarativeDomDocument document2(document);
- QDeclarativeDomDocument document3;
- document3 = document;
-
- QCOMPARE(document.imports().count(), document2.imports().count());
- QCOMPARE(document.errors().count(), document2.errors().count());
- QCOMPARE(document.rootObject().objectClassName(), document2.rootObject().objectClassName());
-
- QCOMPARE(document.imports().count(), document3.imports().count());
- QCOMPARE(document.errors().count(), document3.errors().count());
- QCOMPARE(document.rootObject().objectClassName(), document3.rootObject().objectClassName());
- }
-
- // QDeclarativeDomImport
- {
- QCOMPARE(document.imports().count(), 1);
- QDeclarativeDomImport import = document.imports().at(0);
-
- QDeclarativeDomImport import2(import);
- QDeclarativeDomImport import3;
- import3 = import2;
-
- QCOMPARE(import.type(), import2.type());
- QCOMPARE(import.uri(), import2.uri());
- QCOMPARE(import.version(), import2.version());
- QCOMPARE(import.qualifier(), import2.qualifier());
-
- QCOMPARE(import.type(), import3.type());
- QCOMPARE(import.uri(), import3.uri());
- QCOMPARE(import.version(), import3.version());
- QCOMPARE(import.qualifier(), import3.qualifier());
- }
-
- // QDeclarativeDomObject
- {
- QDeclarativeDomObject object = document.rootObject();
- QVERIFY(object.isValid());
-
- QDeclarativeDomObject object2(object);
- QDeclarativeDomObject object3;
- object3 = object;
-
- QCOMPARE(object.isValid(), object2.isValid());
- QCOMPARE(object.objectType(), object2.objectType());
- QCOMPARE(object.objectClassName(), object2.objectClassName());
- QCOMPARE(object.objectTypeMajorVersion(), object2.objectTypeMajorVersion());
- QCOMPARE(object.objectTypeMinorVersion(), object2.objectTypeMinorVersion());
- QCOMPARE(object.objectId(), object2.objectId());
- QCOMPARE(object.properties().count(), object2.properties().count());
- QCOMPARE(object.dynamicProperties().count(), object2.dynamicProperties().count());
- QCOMPARE(object.isCustomType(), object2.isCustomType());
- QCOMPARE(object.customTypeData(), object2.customTypeData());
- QCOMPARE(object.isComponent(), object2.isComponent());
- QCOMPARE(object.position(), object2.position());
- QCOMPARE(object.length(), object2.length());
- QCOMPARE(object.url(), object2.url());
-
- QCOMPARE(object.isValid(), object3.isValid());
- QCOMPARE(object.objectType(), object3.objectType());
- QCOMPARE(object.objectClassName(), object3.objectClassName());
- QCOMPARE(object.objectTypeMajorVersion(), object3.objectTypeMajorVersion());
- QCOMPARE(object.objectTypeMinorVersion(), object3.objectTypeMinorVersion());
- QCOMPARE(object.objectId(), object3.objectId());
- QCOMPARE(object.properties().count(), object3.properties().count());
- QCOMPARE(object.dynamicProperties().count(), object3.dynamicProperties().count());
- QCOMPARE(object.isCustomType(), object3.isCustomType());
- QCOMPARE(object.customTypeData(), object3.customTypeData());
- QCOMPARE(object.isComponent(), object3.isComponent());
- QCOMPARE(object.position(), object3.position());
- QCOMPARE(object.length(), object3.length());
- QCOMPARE(object.url(), object3.url());
- }
-
- // QDeclarativeDomDynamicProperty
- {
- QDeclarativeDomObject object = document.rootObject();
- QDeclarativeDomDynamicProperty property = object.dynamicProperty("a");
-
- QDeclarativeDomDynamicProperty property2(property);
- QDeclarativeDomDynamicProperty property3;
- property3 = property;
-
- QCOMPARE(property.isValid(), property2.isValid());
- QCOMPARE(property.propertyName(), property2.propertyName());
- QCOMPARE(property.propertyType(), property2.propertyType());
- QCOMPARE(property.propertyTypeName(), property2.propertyTypeName());
- QCOMPARE(property.isDefaultProperty(), property2.isDefaultProperty());
- QCOMPARE(property.defaultValue().propertyName(), property2.defaultValue().propertyName());
- QCOMPARE(property.position(), property2.position());
- QCOMPARE(property.length(), property2.length());
-
- QCOMPARE(property.isValid(), property3.isValid());
- QCOMPARE(property.propertyName(), property3.propertyName());
- QCOMPARE(property.propertyType(), property3.propertyType());
- QCOMPARE(property.propertyTypeName(), property3.propertyTypeName());
- QCOMPARE(property.isDefaultProperty(), property3.isDefaultProperty());
- QCOMPARE(property.defaultValue().propertyName(), property3.defaultValue().propertyName());
- QCOMPARE(property.position(), property3.position());
- QCOMPARE(property.length(), property3.length());
- }
-
- // QDeclarativeDomProperty
- {
- QDeclarativeDomObject object = document.rootObject();
- QDeclarativeDomProperty property = object.property("opacity");
-
- QDeclarativeDomProperty property2(property);
- QDeclarativeDomProperty property3;
- property3 = property;
-
- QCOMPARE(property.isValid(), property2.isValid());
- QCOMPARE(property.propertyName(), property2.propertyName());
- QCOMPARE(property.propertyNameParts(), property2.propertyNameParts());
- QCOMPARE(property.isDefaultProperty(), property2.isDefaultProperty());
- QCOMPARE(property.value().type(), property2.value().type());
- QCOMPARE(property.position(), property2.position());
- QCOMPARE(property.length(), property2.length());
-
- QCOMPARE(property.isValid(), property3.isValid());
- QCOMPARE(property.propertyName(), property3.propertyName());
- QCOMPARE(property.propertyNameParts(), property3.propertyNameParts());
- QCOMPARE(property.isDefaultProperty(), property3.isDefaultProperty());
- QCOMPARE(property.value().type(), property3.value().type());
- QCOMPARE(property.position(), property3.position());
- QCOMPARE(property.length(), property3.length());
- }
-
- // QDeclarativeDomValueLiteral
- {
- QDeclarativeDomObject object = document.rootObject();
- QDeclarativeDomProperty property = object.property("x");
- QDeclarativeDomValueLiteral literal = property.value().toLiteral();
- QCOMPARE(literal.literal(), QString("10"));
-
- QDeclarativeDomValueLiteral literal2(literal);
- QDeclarativeDomValueLiteral literal3;
- literal3 = literal2;
-
- QCOMPARE(literal2.literal(), QString("10"));
- QCOMPARE(literal3.literal(), QString("10"));
- }
-
-
- // QDeclarativeDomValueBinding
- {
- QDeclarativeDomObject object = document.rootObject();
- QDeclarativeDomProperty property = object.property("y");
- QDeclarativeDomValueBinding binding = property.value().toBinding();
- QCOMPARE(binding.binding(), QString("x + 10"));
-
- QDeclarativeDomValueBinding binding2(binding);
- QDeclarativeDomValueBinding binding3;
- binding3 = binding2;
-
- QCOMPARE(binding2.binding(), QString("x + 10"));
- QCOMPARE(binding3.binding(), QString("x + 10"));
- }
-
- // QDeclarativeDomValueValueSource
- {
- QDeclarativeDomObject object = document.rootObject();
- QDeclarativeDomProperty property = object.property("z");
- QDeclarativeDomValueValueSource source = property.value().toValueSource();
- QCOMPARE(source.object().objectClassName(), QByteArray("NumberAnimation"));
-
- QDeclarativeDomValueValueSource source2(source);
- QDeclarativeDomValueValueSource source3;
- source3 = source;
-
- QCOMPARE(source2.object().objectClassName(), QByteArray("NumberAnimation"));
- QCOMPARE(source3.object().objectClassName(), QByteArray("NumberAnimation"));
- }
-
- // QDeclarativeDomValueValueInterceptor
- {
- QDeclarativeDomObject object = document.rootObject();
- QDeclarativeDomProperty property = object.property("opacity");
- QDeclarativeDomValueValueInterceptor interceptor = property.value().toValueInterceptor();
- QCOMPARE(interceptor.object().objectClassName(), QByteArray("Behavior"));
-
- QDeclarativeDomValueValueInterceptor interceptor2(interceptor);
- QDeclarativeDomValueValueInterceptor interceptor3;
- interceptor3 = interceptor;
-
- QCOMPARE(interceptor2.object().objectClassName(), QByteArray("Behavior"));
- QCOMPARE(interceptor3.object().objectClassName(), QByteArray("Behavior"));
- }
-
- // QDeclarativeDomComponent
- {
- QDeclarativeDomObject object = document.rootObject();
- QDeclarativeDomProperty property = object.property("data");
- QCOMPARE(property.value().toList().values().count(), 1);
- QDeclarativeDomComponent component =
- property.value().toList().values().at(0).toObject().toComponent();
- QCOMPARE(component.componentRoot().objectClassName(), QByteArray("Item"));
-
- QDeclarativeDomComponent component2(component);
- QDeclarativeDomComponent component3;
- component3 = component;
-
- QCOMPARE(component.componentRoot().objectClassName(), component2.componentRoot().objectClassName());
- QCOMPARE(component.isValid(), component2.isValid());
- QCOMPARE(component.objectType(), component2.objectType());
- QCOMPARE(component.objectClassName(), component2.objectClassName());
- QCOMPARE(component.objectTypeMajorVersion(), component2.objectTypeMajorVersion());
- QCOMPARE(component.objectTypeMinorVersion(), component2.objectTypeMinorVersion());
- QCOMPARE(component.objectId(), component2.objectId());
- QCOMPARE(component.properties().count(), component2.properties().count());
- QCOMPARE(component.dynamicProperties().count(), component2.dynamicProperties().count());
- QCOMPARE(component.isCustomType(), component2.isCustomType());
- QCOMPARE(component.customTypeData(), component2.customTypeData());
- QCOMPARE(component.isComponent(), component2.isComponent());
- QCOMPARE(component.position(), component2.position());
- QCOMPARE(component.length(), component2.length());
- QCOMPARE(component.url(), component2.url());
-
- QCOMPARE(component.componentRoot().objectClassName(), component3.componentRoot().objectClassName());
- QCOMPARE(component.isValid(), component3.isValid());
- QCOMPARE(component.objectType(), component3.objectType());
- QCOMPARE(component.objectClassName(), component3.objectClassName());
- QCOMPARE(component.objectTypeMajorVersion(), component3.objectTypeMajorVersion());
- QCOMPARE(component.objectTypeMinorVersion(), component3.objectTypeMinorVersion());
- QCOMPARE(component.objectId(), component3.objectId());
- QCOMPARE(component.properties().count(), component3.properties().count());
- QCOMPARE(component.dynamicProperties().count(), component3.dynamicProperties().count());
- QCOMPARE(component.isCustomType(), component3.isCustomType());
- QCOMPARE(component.customTypeData(), component3.customTypeData());
- QCOMPARE(component.isComponent(), component3.isComponent());
- QCOMPARE(component.position(), component3.position());
- QCOMPARE(component.length(), component3.length());
- QCOMPARE(component.url(), component3.url());
- }
-
- // QDeclarativeDomValue
- {
- QDeclarativeDomObject object = document.rootObject();
- QDeclarativeDomProperty property = object.property("data");
- QDeclarativeDomValue value = property.value();
-
- QDeclarativeDomValue value2(value);
- QDeclarativeDomValue value3;
- value3 = value;
-
- QCOMPARE(value.type(), value2.type());
- QCOMPARE(value.isInvalid(), value2.isInvalid());
- QCOMPARE(value.isLiteral(), value2.isLiteral());
- QCOMPARE(value.isBinding(), value2.isBinding());
- QCOMPARE(value.isValueSource(), value2.isValueSource());
- QCOMPARE(value.isValueInterceptor(), value2.isValueInterceptor());
- QCOMPARE(value.isObject(), value2.isObject());
- QCOMPARE(value.isList(), value2.isList());
- QCOMPARE(value.position(), value2.position());
- QCOMPARE(value.length(), value2.length());
-
- QCOMPARE(value.type(), value3.type());
- QCOMPARE(value.isInvalid(), value3.isInvalid());
- QCOMPARE(value.isLiteral(), value3.isLiteral());
- QCOMPARE(value.isBinding(), value3.isBinding());
- QCOMPARE(value.isValueSource(), value3.isValueSource());
- QCOMPARE(value.isValueInterceptor(), value3.isValueInterceptor());
- QCOMPARE(value.isObject(), value3.isObject());
- QCOMPARE(value.isList(), value3.isList());
- QCOMPARE(value.position(), value3.position());
- QCOMPARE(value.length(), value3.length());
- }
- {
- QDeclarativeDomObject object = document.rootObject();
- QDeclarativeDomProperty property = object.property("x");
- QDeclarativeDomValue value = property.value();
-
- QDeclarativeDomValue value2(value);
- QDeclarativeDomValue value3;
- value3 = value;
-
- QCOMPARE(value.type(), value2.type());
- QCOMPARE(value.isInvalid(), value2.isInvalid());
- QCOMPARE(value.isLiteral(), value2.isLiteral());
- QCOMPARE(value.isBinding(), value2.isBinding());
- QCOMPARE(value.isValueSource(), value2.isValueSource());
- QCOMPARE(value.isValueInterceptor(), value2.isValueInterceptor());
- QCOMPARE(value.isObject(), value2.isObject());
- QCOMPARE(value.isList(), value2.isList());
- QCOMPARE(value.position(), value2.position());
- QCOMPARE(value.length(), value2.length());
-
- QCOMPARE(value.type(), value3.type());
- QCOMPARE(value.isInvalid(), value3.isInvalid());
- QCOMPARE(value.isLiteral(), value3.isLiteral());
- QCOMPARE(value.isBinding(), value3.isBinding());
- QCOMPARE(value.isValueSource(), value3.isValueSource());
- QCOMPARE(value.isValueInterceptor(), value3.isValueInterceptor());
- QCOMPARE(value.isObject(), value3.isObject());
- QCOMPARE(value.isList(), value3.isList());
- QCOMPARE(value.position(), value3.position());
- QCOMPARE(value.length(), value3.length());
- }
- {
- QDeclarativeDomValue value;
-
- QDeclarativeDomValue value2(value);
- QDeclarativeDomValue value3;
- value3 = value;
-
- QCOMPARE(value.type(), value2.type());
- QCOMPARE(value.isInvalid(), value2.isInvalid());
- QCOMPARE(value.isLiteral(), value2.isLiteral());
- QCOMPARE(value.isBinding(), value2.isBinding());
- QCOMPARE(value.isValueSource(), value2.isValueSource());
- QCOMPARE(value.isValueInterceptor(), value2.isValueInterceptor());
- QCOMPARE(value.isObject(), value2.isObject());
- QCOMPARE(value.isList(), value2.isList());
- QCOMPARE(value.position(), value2.position());
- QCOMPARE(value.length(), value2.length());
-
- QCOMPARE(value.type(), value3.type());
- QCOMPARE(value.isInvalid(), value3.isInvalid());
- QCOMPARE(value.isLiteral(), value3.isLiteral());
- QCOMPARE(value.isBinding(), value3.isBinding());
- QCOMPARE(value.isValueSource(), value3.isValueSource());
- QCOMPARE(value.isValueInterceptor(), value3.isValueInterceptor());
- QCOMPARE(value.isObject(), value3.isObject());
- QCOMPARE(value.isList(), value3.isList());
- QCOMPARE(value.position(), value3.position());
- QCOMPARE(value.length(), value3.length());
- }
-
- // QDeclarativeDomList
- {
- QDeclarativeDomObject object = document.rootObject();
- QDeclarativeDomProperty property = object.property("children");
- QDeclarativeDomList list = property.value().toList();
- QCOMPARE(list.values().count(), 2);
-
- QDeclarativeDomList list2(list);
- QDeclarativeDomList list3;
- list3 = list2;
-
- QCOMPARE(list.values().count(), list2.values().count());
- QCOMPARE(list.position(), list2.position());
- QCOMPARE(list.length(), list2.length());
- QCOMPARE(list.commaPositions(), list2.commaPositions());
-
- QCOMPARE(list.values().count(), list3.values().count());
- QCOMPARE(list.position(), list3.position());
- QCOMPARE(list.length(), list3.length());
- QCOMPARE(list.commaPositions(), list3.commaPositions());
-
- }
-}
-
-// Tests the position/length of various elements
-void tst_qdeclarativedom::position()
-{
- QByteArray qml = "import QtQuick 1.0\n"
- "Item {\n"
- " id: myItem\n"
- " property int a: 10\n"
- " x: 10\n"
- " y: x + 10\n"
- " NumberAnimation on z {}\n"
- " Behavior on opacity {}\n"
- " Component {\n"
- " Item{}\n"
- " }\n"
- " children: [ Item{}, Item{} ]\n"
- "}\n";
-
-
- QDeclarativeDomDocument document;
- QVERIFY(document.load(&engine, qml));
-
- QDeclarativeDomObject root = document.rootObject();
-
- // All QDeclarativeDomDynamicProperty
- QDeclarativeDomDynamicProperty dynProp = root.dynamicProperty("a");
- QCOMPARE(dynProp.position(), 45);
- QCOMPARE(dynProp.length(), 18);
-
- // All QDeclarativeDomProperty
- QDeclarativeDomProperty x = root.property("x");
- QCOMPARE(x.position(), 68);
- QCOMPARE(x.length(), 1);
-
- QDeclarativeDomProperty y = root.property("y");
- QCOMPARE(y.position(), 78);
- QCOMPARE(y.length(), 1);
-
- QDeclarativeDomProperty z = root.property("z");
- QCOMPARE(z.position(), 111);
- QCOMPARE(z.length(), 1);
-
- QDeclarativeDomProperty opacity = root.property("opacity");
- QCOMPARE(opacity.position(), 132);
- QCOMPARE(opacity.length(), 7);
-
- QDeclarativeDomProperty data = root.property("data");
- QCOMPARE(data.position(), 147);
- QCOMPARE(data.length(), 0);
-
- QDeclarativeDomProperty children = root.property("children");
- QCOMPARE(children.position(), 184);
- QCOMPARE(children.length(), 8);
-
- QDeclarativeDomList dataList = data.value().toList();
- QCOMPARE(dataList.values().count(), 1);
- QDeclarativeDomList childrenList = children.value().toList();
- QCOMPARE(childrenList.values().count(), 2);
-
- // All QDeclarativeDomObject
- QCOMPARE(root.position(), 19);
- QCOMPARE(root.length(), 195);
-
- QDeclarativeDomObject numberAnimation = z.value().toValueSource().object();
- QCOMPARE(numberAnimation.position(), 92);
- QCOMPARE(numberAnimation.length(), 23);
-
- QDeclarativeDomObject behavior = opacity.value().toValueInterceptor().object();
- QCOMPARE(behavior.position(), 120);
- QCOMPARE(behavior.length(), 22);
-
- QDeclarativeDomObject component = dataList.values().at(0).toObject();
- QCOMPARE(component.position(), 147);
- QCOMPARE(component.length(), 32);
-
- QDeclarativeDomObject componentRoot = component.toComponent().componentRoot();
- QCOMPARE(componentRoot.position(), 167);
- QCOMPARE(componentRoot.length(), 6);
-
- QDeclarativeDomObject child1 = childrenList.values().at(0).toObject();
- QCOMPARE(child1.position(), 196);
- QCOMPARE(child1.length(), 6);
-
- QDeclarativeDomObject child2 = childrenList.values().at(1).toObject();
- QCOMPARE(child2.position(), 204);
- QCOMPARE(child2.length(), 6);
-
- // All QDeclarativeDomValue
- QDeclarativeDomValue xValue = x.value();
- QCOMPARE(xValue.position(), 71);
- QCOMPARE(xValue.length(), 2);
-
- QDeclarativeDomValue yValue = y.value();
- QCOMPARE(yValue.position(), 81);
- QCOMPARE(yValue.length(), 6);
-
- QDeclarativeDomValue zValue = z.value();
- QCOMPARE(zValue.position(), 92);
- QCOMPARE(zValue.length(), 23);
-
- QDeclarativeDomValue opacityValue = opacity.value();
- QCOMPARE(opacityValue.position(), 120);
- QCOMPARE(opacityValue.length(), 22);
-
- QDeclarativeDomValue dataValue = data.value();
- QCOMPARE(dataValue.position(), 147);
- QCOMPARE(dataValue.length(), 32);
-
- QDeclarativeDomValue child1Value = childrenList.values().at(0);
- QCOMPARE(child1Value.position(), 196);
- QCOMPARE(child1Value.length(), 6);
-
- QDeclarativeDomValue child2Value = childrenList.values().at(1);
- QCOMPARE(child2Value.position(), 204);
- QCOMPARE(child2Value.length(), 6);
-
- // All QDeclarativeDomList
- QCOMPARE(childrenList.position(), 194);
- QCOMPARE(childrenList.length(), 18);
-}
-
-QTEST_MAIN(tst_qdeclarativedom)
-
-#include "tst_qdeclarativedom.moc"
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/Scope6Nested.qml b/tests/auto/declarative/qdeclarativeecmascript/data/Scope6Nested.qml
new file mode 100644
index 0000000000..a3794df22b
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/Scope6Nested.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ function runtest(obj) {
+ return obj.MyQmlObject.value == 19;
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/SpecialRectangleOne.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/SpecialRectangleOne.qml
new file mode 100644
index 0000000000..698b672259
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/SpecialRectangleOne.qml
@@ -0,0 +1,9 @@
+import QtQuick 1.0
+
+import "importPragmaLibrary.js" as TestPragmaLibraryImport
+
+Rectangle {
+ width: TestPragmaLibraryImport.importIncrementedValue()
+ height: width + 15
+ color: "red"
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/SpecialRectangleTwo.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/SpecialRectangleTwo.qml
new file mode 100644
index 0000000000..581ae671e3
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/SpecialRectangleTwo.qml
@@ -0,0 +1,9 @@
+import QtQuick 1.0
+
+import "importPragmaLibrary.js" as TestPragmaLibraryImport
+
+Rectangle {
+ width: TestPragmaLibraryImport.importIncrementedValue()
+ height: width + 5
+ color: "blue"
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importFive.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importFive.js
new file mode 100644
index 0000000000..e458094552
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importFive.js
@@ -0,0 +1,3 @@
+function importFiveFunction() {
+ return '5';
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importFour.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importFour.js
new file mode 100644
index 0000000000..faddc15c9d
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importFour.js
@@ -0,0 +1,9 @@
+.pragma library
+
+function importFourFunction() {
+ return '4';
+}
+
+function greetingString() {
+ return 'Hello, World!';
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importOne.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importOne.js
new file mode 100644
index 0000000000..338c4e042f
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importOne.js
@@ -0,0 +1,13 @@
+.import "importTwo.js" as ImportTwoJs
+.import "importThree.js" as ImportThreeJs
+
+function greetingString() {
+ if (ImportTwoJs.greetingString().length > 0) {
+ return ImportTwoJs.greetingString();
+ }
+ return ImportThreeJs.greetingString();
+}
+
+function importOneFunction() {
+ return '1';
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importPragmaLibrary.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importPragmaLibrary.js
new file mode 100644
index 0000000000..c746fef14b
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importPragmaLibrary.js
@@ -0,0 +1,9 @@
+.pragma library
+
+var i = 4;
+
+// .pragma library, so should be callable from multiple .qml with shared i.
+function importIncrementedValue() {
+ i = i + 1;
+ return i;
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importThree.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importThree.js
new file mode 100644
index 0000000000..3917134ee2
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importThree.js
@@ -0,0 +1,9 @@
+.import "importFour.js" as ImportFourJs
+
+function greetingString() {
+ return ImportFourJs.greetingString();
+}
+
+function importThreeFunction() {
+ return '3';
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importTwo.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importTwo.js
new file mode 100644
index 0000000000..45b3c9a74d
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importTwo.js
@@ -0,0 +1,10 @@
+.import "importFour.js" as ImportFourJs
+.import "importFive.js" as ImportFiveJs
+
+function greetingString() {
+ return ImportFourJs.greetingString();
+}
+
+function importTwoFunction() {
+ return '2';
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importWithNoImports.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importWithNoImports.js
new file mode 100644
index 0000000000..83426c425c
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/importWithNoImports.js
@@ -0,0 +1,11 @@
+// This js file has no imports, and so should inherit
+// scope from the QML file which includes it.
+
+function componentError() {
+ var i = 5;
+ var errorIsOne = Component.error == 1;
+ if (errorIsOne == true) {
+ i = i + 7;
+ }
+ return i;
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImport.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImport.qml
new file mode 100644
index 0000000000..4a284ad886
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImport.qml
@@ -0,0 +1,14 @@
+import QtQuick 1.0
+
+import "testScriptImport.js" as TestScriptImport
+import "testModuleImport.js" as TestModuleImport
+
+QtObject {
+ id: testQtObject
+
+ property string importedScriptStringValue: TestScriptImport.greetingText
+ property int importedScriptFunctionValue: TestScriptImport.randomInteger(1, 20)
+
+ property int importedModuleAttachedPropertyValue: TestModuleImport.importedAttachedPropertyValue(testQtObject)
+ property int importedModuleEnumValue: TestModuleImport.importedEnumValue
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImportPragmaLibrary.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImportPragmaLibrary.qml
new file mode 100644
index 0000000000..7add311326
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImportPragmaLibrary.qml
@@ -0,0 +1,20 @@
+import QtQuick 1.0
+
+// We use the components specified in SpecialRectangleOne.qml and SpecialRectangleTwo.qml
+
+QtObject {
+ id: testQtObject
+
+ property SpecialRectangleOne a;
+ property SpecialRectangleTwo b;
+
+ a: SpecialRectangleOne {
+ id: rectangleOne
+ }
+ b: SpecialRectangleTwo {
+ id: rectangleTwo
+ }
+
+ // this should be: (5 + 15) + (6 + 5) == 31
+ property int testValue: rectangleOne.height + rectangleTwo.height
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImportScoping.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImportScoping.qml
new file mode 100644
index 0000000000..0df841c78c
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testImportScoping.qml
@@ -0,0 +1,11 @@
+import QtQuick 1.0
+
+// For backward compatibility, importing a script which has no imports,
+// should run the script in the parent context. See QTBUG-17518.
+
+import "importWithNoImports.js" as TestNoImportScoping
+
+QtObject {
+ id: testQtObject
+ property int componentError: TestNoImportScoping.componentError()
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testModuleImport.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testModuleImport.js
new file mode 100644
index 0000000000..69bc1c9887
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testModuleImport.js
@@ -0,0 +1,8 @@
+.import Qt.test 1.0 as JsQtTest // test that we can import elements from .js files
+
+function importedAttachedPropertyValue(obj) {
+ return obj.JsQtTest.MyQmlObject.value; // attached property, value = 19.
+}
+
+var importedEnumValue = JsQtTest.MyQmlObject.EnumValue3 // the actual value of this enum value is "2"
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testScriptImport.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testScriptImport.js
new file mode 100644
index 0000000000..2ecccd8816
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimport/testScriptImport.js
@@ -0,0 +1,11 @@
+.import "importOne.js" as ImportOneJs // test that we can import scripts from .js files
+
+var greetingText = ImportOneJs.greetingString()
+
+function randomInteger(min, max) {
+ if (max > min) {
+ if (min > 10) return min;
+ return max;
+ }
+ return min;
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failFive.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failFive.qml
new file mode 100644
index 0000000000..9bf969cc61
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failFive.qml
@@ -0,0 +1,11 @@
+import QtQuick 1.0
+
+// This should fail, since if the script does have imports
+// of its own, it should run in its own context.
+
+import "importWithImports.js" as TestImportScoping
+
+QtObject {
+ id: testQtObject
+ property int componentError: TestImportScoping.componentError()
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failFour.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failFour.qml
new file mode 100644
index 0000000000..fe7e88a829
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failFour.qml
@@ -0,0 +1,7 @@
+import QtQuick 1.0
+
+import "testModuleImport.js" as TestModuleImport
+
+QtObject {
+ property int importedModuleEnumValue: JsQtTest.MyQmlObject.EnumValue3 // should fail - the typenames available in TestModuleImport should not be available in this scope
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failOne.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failOne.qml
new file mode 100644
index 0000000000..e7fb7656f0
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failOne.qml
@@ -0,0 +1,7 @@
+import QtQuick 1.0
+
+import "testScriptImport.js" as TestScriptImport
+
+QtObject {
+ property string importScriptFunctionValue: TestScriptImport.ImportOneJs.greetingString() // should fail - the context of TestScriptImport is private to TestScriptImport.
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failThree.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failThree.qml
new file mode 100644
index 0000000000..fa720a64eb
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failThree.qml
@@ -0,0 +1,8 @@
+import QtQuick 1.0
+
+import "testModuleImport.js" as TestModuleImport
+
+QtObject {
+ id: testQtObject
+ property int importedModuleAttachedPropertyValue: testQtObject.TestModuleImport.JsQtTest.MyQmlObject.value // should fail - the context of TestScriptImport is private to TestScriptImport.
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failTwo.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failTwo.qml
new file mode 100644
index 0000000000..c2cbce9f80
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/failTwo.qml
@@ -0,0 +1,7 @@
+import QtQuick 1.0
+
+import "testScriptImport.js" as TestScriptImport
+
+QtObject {
+ property string importScriptFunctionValue: ImportOneJs.greetingString() // should fail - the typenames in TestScriptImport should not be visible from this scope
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importOne.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importOne.js
new file mode 100644
index 0000000000..45fd9c75dd
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importOne.js
@@ -0,0 +1,7 @@
+function greetingString() {
+ return 'Hello, World!';
+}
+
+function importOneFunction() {
+ return '1';
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importPragmaLibrary.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importPragmaLibrary.js
new file mode 100644
index 0000000000..ad0e6946a2
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importPragmaLibrary.js
@@ -0,0 +1,11 @@
+.pragma library
+
+// .pragma library, so shouldn't inherit imports from any .qml file.
+function importValue() {
+ var i = 3;
+ var errorIsOne = Component.error == 1; // this line should fail.
+ if (errorIsOne == true) {
+ i = i + 4;
+ }
+ return i;
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importWithImports.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importWithImports.js
new file mode 100644
index 0000000000..6d77ceccb1
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/importWithImports.js
@@ -0,0 +1,13 @@
+.import "importOne.js" as ImportOne
+
+// This js file has imports, so should not inherit
+// scope from the QML file which includes it.
+
+function componentError() {
+ var i = 3;
+ var errorIsOne = Component.error == 1; // this line should fail.
+ if (errorIsOne == true) {
+ i = i + 4;
+ }
+ return i;
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testImportPragmaLibrary.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testImportPragmaLibrary.qml
new file mode 100644
index 0000000000..7e4a73ae42
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testImportPragmaLibrary.qml
@@ -0,0 +1,8 @@
+import QtQuick 1.0
+
+import "importPragmaLibrary.js" as ImportPragmaLibrary
+
+QtObject {
+ id: testQtObject
+ property int testValue: ImportPragmaLibrary.importValue()
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testModuleImport.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testModuleImport.js
new file mode 100644
index 0000000000..69bc1c9887
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testModuleImport.js
@@ -0,0 +1,8 @@
+.import Qt.test 1.0 as JsQtTest // test that we can import elements from .js files
+
+function importedAttachedPropertyValue(obj) {
+ return obj.JsQtTest.MyQmlObject.value; // attached property, value = 19.
+}
+
+var importedEnumValue = JsQtTest.MyQmlObject.EnumValue3 // the actual value of this enum value is "2"
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testScriptImport.js b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testScriptImport.js
new file mode 100644
index 0000000000..2ecccd8816
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsimportfail/testScriptImport.js
@@ -0,0 +1,11 @@
+.import "importOne.js" as ImportOneJs // test that we can import scripts from .js files
+
+var greetingText = ImportOneJs.greetingString()
+
+function randomInteger(min, max) {
+ if (max > min) {
+ if (min > 10) return min;
+ return max;
+ }
+ return min;
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/moduleApi.qml b/tests/auto/declarative/qdeclarativeecmascript/data/moduleApi.qml
new file mode 100644
index 0000000000..62abcb7d83
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/moduleApi.qml
@@ -0,0 +1,18 @@
+import QtQuick 1.0
+
+import Qt.test 1.0 as QtTest // module API installed into existing uri
+import Qt.test.scriptApi 1.0 as QtTestScriptApi // script module API installed into new uri
+import Qt.test.qobjectApi 1.0 as QtTestQObjectApi // qobject module API installed into new uri
+import Qt.test.qobjectApi 1.3 as QtTestMinorVersionQObjectApi // qobject module API installed into existing uri with new minor version
+import Qt.test.qobjectApi 2.0 as QtTestMajorVersionQObjectApi // qobject module API installed into existing uri with new major version
+import Qt.test.qobjectApiParented 1.0 as QtTestParentedQObjectApi // qobject (with parent) module API installed into a new uri
+
+QtObject {
+ property int existingUriTest: QtTest.qobjectTestProperty
+ property int scriptTest: QtTestScriptApi.scriptTestProperty
+ property int qobjectTest: QtTestQObjectApi.qobjectTestProperty
+ property int qobjectMinorVersionTest: QtTestMinorVersionQObjectApi.qobjectTestProperty
+ property int qobjectMajorVersionTest: QtTestMajorVersionQObjectApi.qobjectTestProperty
+ property int qobjectParentedTest: QtTestParentedQObjectApi.qobjectTestProperty
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiCaching.qml b/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiCaching.qml
new file mode 100644
index 0000000000..9cee8c3065
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiCaching.qml
@@ -0,0 +1,12 @@
+import QtQuick 1.0
+
+import Qt.test 1.0 as QtTest // module API installed into existing uri
+import Qt.test.scriptApi 1.0 as QtTestScriptApi // script module API installed into new uri
+import Qt.test.qobjectApiParented 1.0 as QtTestParentedQObjectApi // qobject (with parent) module API installed into a new uri
+
+QtObject {
+ property int existingUriTest: QtTest.qobjectTestProperty
+ property int scriptTest: QtTestScriptApi.scriptTestProperty
+ property int qobjectParentedTest: QtTestParentedQObjectApi.qobjectTestProperty
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiMajorVersionFail.qml b/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiMajorVersionFail.qml
new file mode 100644
index 0000000000..eca29ab2cf
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiMajorVersionFail.qml
@@ -0,0 +1,10 @@
+import QtQuick 1.0
+
+// this qml file attempts to import an invalid version of a qobject module API.
+
+import Qt.test.qobjectApi 4.0 as QtTestMajorVersionQObjectApi // qobject module API installed into existing uri with nonexistent major version
+
+QtObject {
+ property int qobjectMajorVersionTest: QtTestMajorVersionQObjectApi.qobjectTestProperty
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiMinorVersionFail.qml b/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiMinorVersionFail.qml
new file mode 100644
index 0000000000..e360bd1668
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiMinorVersionFail.qml
@@ -0,0 +1,10 @@
+import QtQuick 1.0
+
+// this qml file attempts to import an invalid version of a qobject module API.
+
+import Qt.test.qobjectApi 1.2 as QtTestMinorVersionQObjectApi // qobject module API installed into existing uri with nonexistent minor version
+
+QtObject {
+ property int qobjectMinorVersionTest: QtTestMinorVersionedQObjectApi.qobjectTestProperty
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiWriting.qml b/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiWriting.qml
new file mode 100644
index 0000000000..90a674681c
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/moduleApiWriting.qml
@@ -0,0 +1,27 @@
+import QtQuick 1.0
+
+import Qt.test 1.0 as QtTest // module API installed into existing uri
+
+QtObject {
+ property int firstProperty: 1
+ property int secondProperty: 2
+ property int readOnlyProperty: QtTest.qobjectTestProperty
+ property int writableProperty: QtTest.qobjectTestWritableProperty
+
+ onFirstPropertyChanged: {
+ // In this case, we want to attempt to set the module API property.
+ // This should fail, as the module API property is read only.
+ if (firstProperty != QtTest.qobjectTestProperty) {
+ QtTest.qobjectTestProperty = firstProperty; // should silently fail.
+ }
+ }
+
+ onSecondPropertyChanged: {
+ // In this case, we want to attempt to set the module API property.
+ // This should succeed, as the module API property is writable.
+ if (secondProperty != QtTest.qobjectTestWritableProperty) {
+ QtTest.qobjectTestWritableProperty = secondProperty; // should succeed.
+ }
+ }
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/realToInt.qml b/tests/auto/declarative/qdeclarativeecmascript/data/realToInt.qml
new file mode 100644
index 0000000000..cbbbbf921a
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/realToInt.qml
@@ -0,0 +1,11 @@
+import QtQuick 1.0
+import Qt.test 1.0
+
+MyQmlObject {
+ function test1() {
+ value = 4.2
+ }
+ function test2() {
+ value = 7.9
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/ScarceResourceSignalComponent.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/ScarceResourceSignalComponent.qml
new file mode 100644
index 0000000000..fb40bdc2de
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/ScarceResourceSignalComponent.qml
@@ -0,0 +1,9 @@
+import QtQuick 1.0
+
+QtObject {
+ property variant scarceResourceCopy
+ property int width: 5
+ signal testSignal
+ signal testSignal2
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopy.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopy.qml
new file mode 100644
index 0000000000..82184354d8
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopy.qml
@@ -0,0 +1,15 @@
+import QtQuick 1.0
+import Qt.test 1.0
+
+// Here we import a scarce resource directly.
+// The instance has a property which is a copy
+// of the scarce resource, so it should not be
+// detached (but we should automatically release
+// the resource from our engine internal list).
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant scarceResourceCopy: scarceResourceProvider.scarceResource
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyFromJs.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyFromJs.qml
new file mode 100644
index 0000000000..60c26ac4f2
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyFromJs.qml
@@ -0,0 +1,15 @@
+import QtQuick 1.0
+import Qt.test 1.0
+import "scarceResourceTest.js" as ScarceResourceProviderJs
+
+// Here we import a scarce resource directly, from JS module.
+// It is not preserved or released manually, so it should be
+// automatically released once evaluation of the binding
+// is complete.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant scarceResourceCopy: ScarceResourceProviderJs.importScarceResource(scarceResourceProvider)
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.js b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.js
new file mode 100644
index 0000000000..bacc50dcc9
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.js
@@ -0,0 +1,24 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, the "retn" variable will be evaluated during import.
+// Since the "importScarceResource()" function depends on this variable,
+// we must explicitly preserve the "retn" variable or the scarce
+// resource would automatically be released after import completes
+// but before the binding is evaluated.
+
+var component = Qt.createComponent("scarceResourceCopy.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
+retn.preserve(); // must preserve manually or it will be released!
+
+function importScarceResource() {
+ // if called prior to calling destroyScarceResource(),
+ // this function should return the preserved scarce resource.
+ // otherwise, it should return an invalid variant.
+ return retn;
+}
+
+function destroyScarceResource() {
+ retn.destroy();
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.qml
new file mode 100644
index 0000000000..0513b0840e
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.qml
@@ -0,0 +1,18 @@
+import QtQuick 1.0
+import Qt.test 1.0
+import "scarceResourceCopyImport.js" as ScarceResourceCopyImportJs
+
+QtObject {
+ // this binding is evaluated once, prior to the resource being released
+ property variant scarceResourceCopy: ScarceResourceCopyImportJs.importScarceResource()
+
+ // this code is evaluated on completion, and so copy one should be valid, copy two invalid.
+ property variant scarceResourceAssignedCopyOne;
+ property variant scarceResourceAssignedCopyTwo;
+ Component.onCompleted: {
+ scarceResourceAssignedCopyOne = ScarceResourceCopyImportJs.importScarceResource();
+ ScarceResourceCopyImportJs.destroyScarceResource();
+ scarceResourceAssignedCopyTwo = ScarceResourceCopyImportJs.importScarceResource();
+ }
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.js b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.js
new file mode 100644
index 0000000000..6c495863b5
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.js
@@ -0,0 +1,18 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, the "retn" variable will be evaluated during import.
+// Since the importScarceResource() function depends on this variable,
+// because we DO NOT call "retn.preserve()", the scarce resource will
+// be released after the import completes but prior to evaluation of
+// any binding which calls "importScarceResource()".
+// Thus, "importScarceResource()" will return a released (invalid)
+// scarce resource.
+
+var component = Qt.createComponent("scarceResourceCopy.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
+
+function importScarceResource() {
+ return retn; // should return a released (invalid) scarce resource
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.qml
new file mode 100644
index 0000000000..d3c4d4ed65
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.qml
@@ -0,0 +1,8 @@
+import QtQuick 1.0
+import Qt.test 1.0
+import "scarceResourceCopyImportFail.js" as ScarceResourceCopyImportFailJs
+
+QtObject {
+ property variant scarceResourceCopy: ScarceResourceCopyImportFailJs.importScarceResource()
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.js b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.js
new file mode 100644
index 0000000000..4a5b6b4427
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.js
@@ -0,0 +1,14 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, the "retn" variable will be evaluated during import.
+// Since the importScarceResource() function depends on this variable,
+// because we DO NOT call "retn.preserve()", the scarce resource will
+// be released after the import completes but prior to evaluation of
+// any binding which calls "importScarceResource()".
+// Thus, "importScarceResource()" will return a released (invalid)
+// scarce resource.
+
+var component = Qt.createComponent("scarceResourceCopyNoBinding.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.qml
new file mode 100644
index 0000000000..72cd4dac8a
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.qml
@@ -0,0 +1,12 @@
+import QtQuick 1.0
+import Qt.test 1.0
+
+// the following js import doesn't manually preserve or destroy any resources
+import "scarceResourceCopyImportNoBinding.js" as ScarceResourceCopyImportNoBindingJs
+
+QtObject {
+ // in this case, there is an import but no binding evaluated.
+ // nonetheless, any resources which are not preserved, should
+ // be automatically released by the engine.
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyNoBinding.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyNoBinding.qml
new file mode 100644
index 0000000000..681a382427
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyNoBinding.qml
@@ -0,0 +1,14 @@
+import QtQuick 1.0
+import Qt.test 1.0
+
+QtObject {
+ // this component doesn't bind any property to a scarce
+ // resource from the scarce resource provider,
+ // so the binding evaluation resource cleanup
+ // codepath shouldn't be activated; so if the resources
+ // are released, it will be due to the import evaluation
+ // resource cleanup codepath being activated correctly.
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceDestroyedCopy.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceDestroyedCopy.qml
new file mode 100644
index 0000000000..87ceda9d7a
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceDestroyedCopy.qml
@@ -0,0 +1,14 @@
+import QtQuick 1.0
+import Qt.test 1.0
+import "scarceResourceTest.js" as ScarceResourceProviderJs
+
+// In this case, following the evaluation of the binding,
+// the scarceResourceTest value should be an invalid variant,
+// since the scarce resource will have been released.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant scarceResourceCopy: ScarceResourceProviderJs.importReleasedScarceResource(scarceResourceProvider);
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunction.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunction.qml
new file mode 100644
index 0000000000..e3e7aed9ee
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunction.qml
@@ -0,0 +1,23 @@
+import QtQuick 1.0
+import Qt.test 1.0
+
+// Here we import a scarce resource directly.
+// The copy is only assigned when retrieveScarceResource()
+// is called, and so should be detached prior to that.
+// The copy should be released when releaseScarceResource()
+// is called, and so should be detached after that.
+
+QtObject {
+ id: root
+ property MyScarceResourceObject a: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant scarceResourceCopy;
+
+ function retrieveScarceResource() {
+ root.scarceResourceCopy = scarceResourceProvider.scarceResource;
+ }
+
+ function releaseScarceResource() {
+ root.scarceResourceCopy = null;
+ }
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunctionFail.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunctionFail.qml
new file mode 100644
index 0000000000..b1342fea90
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunctionFail.qml
@@ -0,0 +1,23 @@
+import QtQuick 1.0
+import Qt.test 1.0
+
+// In this example, a common syntax error will only be "caught"
+// when the function is called via:
+// QDeclarativeVMEMetaObject::metaCall->invokeMetaMethod()
+// We would like to ensure that a useful error message is printed,
+// rather than having QScriptValue::call() function fail silently.
+
+QtObject {
+ id: root
+ property MyScarceResourceObject a: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant scarceResourceCopy;
+
+ function retrieveScarceResource() {
+ root.scarceResourceCopy = scarceResourceProvider.scarceResource(); // common syntax error, should throw exception
+ }
+
+ function releaseScarceResource() {
+ root.scarceResourceCopy = null;
+ }
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceSignal.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceSignal.qml
new file mode 100644
index 0000000000..9c920b1aa0
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceSignal.qml
@@ -0,0 +1,29 @@
+import QtQuick 1.0
+import Qt.test 1.0
+
+QtObject {
+ id: root
+
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+
+ property ScarceResourceSignalComponent b;
+ b: ScarceResourceSignalComponent {
+ objectName: "srsc"
+
+ onTestSignal: {
+ // this signal will be invoked manually in the test.
+ // the scarce resource should be released automatically after evaluation
+ // and since we don't keep a copy of it, the pixmap will be detached.
+ width = (scarceResourceProvider.scarceResource,10)
+ }
+
+ onTestSignal2: {
+ // this signal will be invoked manually in the test.
+ // the scarce resource should be released automatically after evaluation
+ // but since we assign it to a property, the pixmap won't be detached.
+ scarceResourceCopy = scarceResourceProvider.scarceResource
+ }
+ }
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.js b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.js
new file mode 100644
index 0000000000..c904eb3564
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.js
@@ -0,0 +1,48 @@
+.import Qt.test 1.0 as JsQtTest
+
+function importScarceResource(scarceResourceProvider) {
+ // the scarce resource should be automatically released
+ // after the binding is evaluated if preserve is not
+ // called.
+ return scarceResourceProvider.scarceResource;
+}
+
+function importPreservedScarceResource(scarceResourceProvider) {
+ // the scarce resource is manually preserved
+ // during the evaluation of the binding.
+ // it should not be released.
+ var scarceResource = scarceResourceProvider.scarceResource;
+ scarceResource.preserve();
+ return scarceResource;
+}
+
+function importReleasedScarceResource(scarceResourceProvider) {
+ // release the scarce resource during the
+ // evaluation of the binding. The returned
+ // variant will therefore be invalid.
+ var scarceResource = scarceResourceProvider.scarceResource;
+ scarceResource.destroy();
+ return scarceResource;
+}
+
+function importPreservedScarceResourceFromMultiple(scarceResourceProvider) {
+ // some scarce resources are manually preserved,
+ // some of them are manually destroyed,
+ // and some are automatically managed.
+ // We return a preserved resource
+ var sr1 = scarceResourceProvider.scarceResource; // preserved/destroyed.
+ sr1.preserve();
+ var sr2 = scarceResourceProvider.scarceResource; // preserved/destroyed
+ sr2.preserve();
+ var sr3 = scarceResourceProvider.scarceResource; // automatic.
+ var sr4 = scarceResourceProvider.scarceResource; // automatic and returned.
+ var sr5 = scarceResourceProvider.scarceResource; // destroyed
+ sr5.destroy();
+ sr2.destroy();
+ var sr6 = scarceResourceProvider.scarceResource; // destroyed
+ var sr7 = scarceResourceProvider.scarceResource; // automatic
+ sr1.destroy();
+ sr6.destroy();
+ return sr4;
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.qml
new file mode 100644
index 0000000000..3775172c04
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.qml
@@ -0,0 +1,14 @@
+import QtQuick 1.0
+import Qt.test 1.0
+
+// Here we import a scarce resource directly, and use it in a binding.
+// It is not preserved or released manually, so it should be
+// automatically released once evaluation of the binding
+// is complete.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property int scarceResourceTest: scarceResourceProvider.scarceResource,100 // return 100, but include the scarceResource in the binding to be evaluated.
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestMultiple.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestMultiple.qml
new file mode 100644
index 0000000000..3139382b05
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestMultiple.qml
@@ -0,0 +1,16 @@
+import QtQuick 1.0
+import Qt.test 1.0
+import "scarceResourceTest.js" as ScarceResourceProviderJs
+
+// In this case, multiple scarce resource are explicity preserved
+// and then explicitly destroyed, while others are automatically
+// managed. Since none are manually preserved without subsequently
+// being destroyed, after the evaluation of the binding the
+// scarce resource should be detached.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property int scarceResourceTest: ScarceResourceProviderJs.importPreservedScarceResourceFromMultiple(scarceResourceProvider), 100
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestPreserve.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestPreserve.qml
new file mode 100644
index 0000000000..d810377a51
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestPreserve.qml
@@ -0,0 +1,15 @@
+import QtQuick 1.0
+import Qt.test 1.0
+import "scarceResourceTest.js" as ScarceResourceProviderJs
+
+// In this case, the scarce resource is explicity preserved.
+// It should not be automatically released after the evaluation
+// of the binding is complete, but instead will be kept in
+// memory until the JS garbage collector runs.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property int scarceResourceTest: ScarceResourceProviderJs.importPreservedScarceResource(scarceResourceProvider),100 // return 100, but the resource should be preserved.
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scope.5.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scope.5.qml
new file mode 100644
index 0000000000..405746c459
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scope.5.qml
@@ -0,0 +1,27 @@
+import QtQuick 1.0
+
+Item {
+ property bool test1: false;
+ property bool test2: false;
+
+ property int a: 10
+
+ Item {
+ id: nested
+ property int a: 11
+
+ function mynestedfunction() {
+ return a;
+ }
+ }
+
+ function myouterfunction() {
+ return a;
+ }
+
+ Component.onCompleted: {
+ test1 = (myouterfunction() == 10);
+ test2 = (nested.mynestedfunction() == 11);
+ }
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scope.6.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scope.6.qml
new file mode 100644
index 0000000000..1c81e4e945
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/scope.6.qml
@@ -0,0 +1,10 @@
+import QtQuick 1.0
+
+Item {
+ id: me
+ property bool test: nested.runtest(me);
+
+ Scope6Nested {
+ id: nested
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
index 1d65b15476..7256d442e3 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp
@@ -41,6 +41,8 @@
#include "testtypes.h"
#include <QWidget>
#include <QPlainTextEdit>
+#include <QDeclarativeEngine>
+#include <QScriptEngine>
class BaseExtensionObject : public QObject
{
@@ -99,6 +101,37 @@ public:
void setWidth(int) { }
};
+static QScriptValue script_api(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ static int testProperty = 13;
+ QScriptValue v = scriptEngine->newObject();
+ v.setProperty("scriptTestProperty", testProperty++);
+ return v;
+}
+
+static QObject *qobject_api(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ testQObjectApi *o = new testQObjectApi();
+ o->setQObjectTestProperty(20);
+ o->setQObjectTestWritableProperty(50);
+ return o;
+}
+
+static QObject *qobject_api_engine_parent(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+{
+ Q_UNUSED(scriptEngine)
+
+ static int testProperty = 26;
+ testQObjectApi *o = new testQObjectApi(engine);
+ o->setQObjectTestProperty(testProperty++);
+ return o;
+}
void registerTypes()
{
@@ -116,6 +149,9 @@ void registerTypes()
qmlRegisterType<MyRevisionedClass>("Qt.test",1,0,"MyRevisionedClass");
qmlRegisterType<MyRevisionedClass,1>("Qt.test",1,1,"MyRevisionedClass");
+ // test scarce resource property binding post-evaluation optimisation
+ qmlRegisterType<ScarceResourceObject>("Qt.test", 1,0, "MyScarceResourceObject");
+
// Register the uncreatable base class
qmlRegisterRevision<MyRevisionedBaseClassRegistered,1>("Qt.test",1,1);
// MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
@@ -127,6 +163,15 @@ void registerTypes()
qmlRegisterType<QPlainTextEdit>("Qt.test",1,0,"QPlainTextEdit");
qRegisterMetaType<MyQmlObject::MyType>("MyQmlObject::MyType");
+
+ qmlRegisterModuleApi("Qt.test",1,0,script_api); // register (script) module API for an existing uri which contains elements
+ qmlRegisterModuleApi("Qt.test",1,0,qobject_api); // register (qobject) for an existing uri for which another module API was previously regd. Should replace!
+ qmlRegisterModuleApi("Qt.test.scriptApi",1,0,script_api); // register (script) module API for a uri which doesn't contain elements
+ qmlRegisterModuleApi("Qt.test.qobjectApi",1,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements
+ qmlRegisterModuleApi("Qt.test.qobjectApi",1,3,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, minor version set
+ qmlRegisterModuleApi("Qt.test.qobjectApi",2,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, major version set
+ qmlRegisterModuleApi("Qt.test.qobjectApiParented",1,0,qobject_api_engine_parent); // register (parented qobject) module API for a uri which doesn't contain elements
+
qRegisterMetaType<MyQmlObject::MyType>("MyEnum2");
qRegisterMetaType<Qt::MouseButtons>("Qt::MouseButtons");
}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
index ad38d279bb..320e60c82a 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
+++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h
@@ -51,6 +51,7 @@
#include <QtGui/qmatrix.h>
#include <QtGui/qcolor.h>
#include <QtGui/qvector3d.h>
+#include <QtGui/QPixmap>
#include <QtCore/qdatetime.h>
#include <QtScript/qscriptvalue.h>
#include <QtDeclarative/qdeclarativescriptstring.h>
@@ -909,6 +910,56 @@ QML_DECLARE_TYPE(MyRevisionedClass)
QML_DECLARE_TYPE(MyRevisionedSubclass)
Q_DECLARE_METATYPE(MyQmlObject::MyType)
+
+class ScarceResourceObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QPixmap scarceResource READ scarceResource WRITE setScarceResource NOTIFY scarceResourceChanged)
+public:
+ ScarceResourceObject(QObject *parent = 0) : QObject(parent), m_value(100, 100) { m_value.fill(Qt::blue); }
+ ~ScarceResourceObject() {}
+
+ QPixmap scarceResource() const { return m_value; }
+ void setScarceResource(QPixmap v) { m_value = v; emit scarceResourceChanged(); }
+
+ bool scarceResourceIsDetached() const { return m_value.isDetached(); }
+
+signals:
+ void scarceResourceChanged();
+
+private:
+ QPixmap m_value;
+};
+
+class testQObjectApi : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY (int qobjectTestProperty READ qobjectTestProperty NOTIFY qobjectTestPropertyChanged)
+ Q_PROPERTY (int qobjectTestWritableProperty READ qobjectTestWritableProperty WRITE setQObjectTestWritableProperty NOTIFY qobjectTestWritablePropertyChanged)
+
+public:
+ testQObjectApi(QObject* parent = 0)
+ : QObject(parent), m_testProperty(0)
+ {
+ }
+
+ ~testQObjectApi() {}
+
+ int qobjectTestProperty() const { return m_testProperty; }
+ void setQObjectTestProperty(int tp) { m_testProperty = tp; emit qobjectTestPropertyChanged(tp); }
+
+ int qobjectTestWritableProperty() const { return m_testWritableProperty; }
+ void setQObjectTestWritableProperty(int tp) { m_testWritableProperty = tp; emit qobjectTestWritablePropertyChanged(tp); }
+
+signals:
+ void qobjectTestPropertyChanged(int testProperty);
+ void qobjectTestWritablePropertyChanged(int testWritableProperty);
+
+private:
+ int m_testProperty;
+ int m_testWritableProperty;
+};
+
void registerTypes();
#endif // TESTTYPES_H
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
index 1ec12fec01..efa95d36b6 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
@@ -144,6 +144,9 @@ private slots:
void numberAssignment();
void propertySplicing();
void signalWithUnknownTypes();
+ void moduleApi();
+ void importScripts();
+ void scarceResources();
void bug1();
void bug2();
@@ -176,6 +179,7 @@ private slots:
void aliasBindingsOverrideTarget();
void aliasWritesOverrideBindings();
void pushCleanContext();
+ void realToInt();
void include();
@@ -260,6 +264,7 @@ void tst_qdeclarativeecmascript::idShortcutInvalidates()
QVERIFY(object->objectProperty() != 0);
delete object->objectProperty();
QVERIFY(object->objectProperty() == 0);
+ delete object;
}
{
@@ -269,6 +274,7 @@ void tst_qdeclarativeecmascript::idShortcutInvalidates()
QVERIFY(object->objectProperty() != 0);
delete object->objectProperty();
QVERIFY(object->objectProperty() == 0);
+ delete object;
}
}
@@ -279,12 +285,14 @@ void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->stringProperty(), QLatin1String("pass"));
+ delete object;
}
{
QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->stringProperty(), QLatin1String("pass"));
+ delete object;
}
}
@@ -297,6 +305,7 @@ void tst_qdeclarativeecmascript::signalAssignment()
QCOMPARE(object->string(), QString());
emit object->basicSignal();
QCOMPARE(object->string(), QString("pass"));
+ delete object;
}
{
@@ -306,6 +315,7 @@ void tst_qdeclarativeecmascript::signalAssignment()
QCOMPARE(object->string(), QString());
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
+ delete object;
}
}
@@ -320,6 +330,7 @@ void tst_qdeclarativeecmascript::methods()
emit object->basicSignal();
QCOMPARE(object->methodCalled(), true);
QCOMPARE(object->methodIntCalled(), false);
+ delete object;
}
{
@@ -331,6 +342,7 @@ void tst_qdeclarativeecmascript::methods()
emit object->basicSignal();
QCOMPARE(object->methodCalled(), false);
QCOMPARE(object->methodIntCalled(), true);
+ delete object;
}
{
@@ -338,6 +350,7 @@ void tst_qdeclarativeecmascript::methods()
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("test").toInt(), 19);
+ delete object;
}
{
@@ -347,6 +360,7 @@ void tst_qdeclarativeecmascript::methods()
QCOMPARE(object->property("test").toInt(), 19);
QCOMPARE(object->property("test2").toInt(), 17);
QCOMPARE(object->property("test3").toInt(), 16);
+ delete object;
}
{
@@ -354,6 +368,7 @@ void tst_qdeclarativeecmascript::methods()
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("test").toInt(), 9);
+ delete object;
}
}
@@ -364,6 +379,7 @@ void tst_qdeclarativeecmascript::bindingLoop()
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
QObject *object = component.create();
QVERIFY(object != 0);
+ delete object;
}
void tst_qdeclarativeecmascript::basicExpressions_data()
@@ -508,6 +524,7 @@ void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
}
+ delete object3;
}
void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
@@ -582,6 +599,8 @@ void tst_qdeclarativeecmascript::deferredProperties()
QCOMPARE(qmlObject->value(), 10);
object->setValue(19);
QCOMPARE(qmlObject->value(), 19);
+
+ delete object;
}
// Check errors on deferred properties are correctly emitted
@@ -625,6 +644,7 @@ void tst_qdeclarativeecmascript::extensionObjects()
QCOMPARE(nested->coreProperty(), 11);
QCOMPARE(nested->baseProperty(), 92);
+ delete object;
}
void tst_qdeclarativeecmascript::overrideExtensionProperties()
@@ -635,6 +655,8 @@ void tst_qdeclarativeecmascript::overrideExtensionProperties()
QVERIFY(object != 0);
QVERIFY(object->secondProperty() != 0);
QVERIFY(object->firstProperty() == 0);
+
+ delete object;
}
void tst_qdeclarativeecmascript::attachedProperties()
@@ -647,6 +669,7 @@ void tst_qdeclarativeecmascript::attachedProperties()
QCOMPARE(object->property("b").toInt(), 19);
QCOMPARE(object->property("c").toInt(), 19);
QCOMPARE(object->property("d").toInt(), 19);
+ delete object;
}
{
@@ -671,6 +694,7 @@ void tst_qdeclarativeecmascript::attachedProperties()
QVERIFY(attached != 0);
QCOMPARE(attached->value2(), 9);
+ delete object;
}
}
@@ -692,6 +716,8 @@ void tst_qdeclarativeecmascript::enums()
QCOMPARE(object->property("h").toInt(), 3);
QCOMPARE(object->property("i").toInt(), 19);
QCOMPARE(object->property("j").toInt(), 19);
+
+ delete object;
}
// Non-existent enums
{
@@ -706,6 +732,8 @@ void tst_qdeclarativeecmascript::enums()
QVERIFY(object != 0);
QCOMPARE(object->property("a").toInt(), 0);
QCOMPARE(object->property("b").toInt(), 0);
+
+ delete object;
}
}
@@ -716,6 +744,8 @@ void tst_qdeclarativeecmascript::valueTypeFunctions()
QVERIFY(obj != 0);
QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
+
+ delete obj;
}
/*
@@ -739,6 +769,8 @@ void tst_qdeclarativeecmascript::constantsOverrideBindings()
QCOMPARE(object->property("c2").toInt(), 13);
object->setProperty("c1", QVariant(8));
QCOMPARE(object->property("c2").toInt(), 13);
+
+ delete object;
}
// During construction
@@ -752,6 +784,8 @@ void tst_qdeclarativeecmascript::constantsOverrideBindings()
object->setProperty("c1", QVariant(9));
QCOMPARE(object->property("c1").toInt(), 9);
QCOMPARE(object->property("c2").toInt(), 10);
+
+ delete object;
}
#if 0
@@ -770,6 +804,8 @@ void tst_qdeclarativeecmascript::constantsOverrideBindings()
object->setProperty("c1", QVariant(7));
QCOMPARE(object->property("c1").toInt(), 7);
QCOMPARE(object->property("c2").toInt(), 13);
+
+ delete object;
}
#endif
@@ -784,6 +820,8 @@ void tst_qdeclarativeecmascript::constantsOverrideBindings()
object->setProperty("c1", QVariant(9));
QCOMPARE(object->property("c1").toInt(), 9);
QCOMPARE(object->property("c3").toInt(), 10);
+
+ delete object;
}
}
@@ -811,6 +849,8 @@ void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
QCOMPARE(object->property("c1").toInt(), 9);
QCOMPARE(object->property("c2").toInt(), 8);
QCOMPARE(object->property("c3").toInt(), 8);
+
+ delete object;
}
/*
@@ -827,6 +867,8 @@ void tst_qdeclarativeecmascript::nonExistentAttachedObject()
QObject *object = component.create();
QVERIFY(object != 0);
+
+ delete object;
}
void tst_qdeclarativeecmascript::scope()
@@ -846,6 +888,8 @@ void tst_qdeclarativeecmascript::scope()
QCOMPARE(object->property("test8").toInt(), 2);
QCOMPARE(object->property("test9").toInt(), 1);
QCOMPARE(object->property("test10").toInt(), 3);
+
+ delete object;
}
{
@@ -859,6 +903,8 @@ void tst_qdeclarativeecmascript::scope()
QCOMPARE(object->property("test4").toInt(), 14);
QCOMPARE(object->property("test5").toInt(), 24);
QCOMPARE(object->property("test6").toInt(), 24);
+
+ delete object;
}
{
@@ -869,6 +915,8 @@ void tst_qdeclarativeecmascript::scope()
QCOMPARE(object->property("test1").toBool(), true);
QCOMPARE(object->property("test2").toBool(), true);
QCOMPARE(object->property("test3").toBool(), true);
+
+ delete object;
}
// Signal argument scope
@@ -887,6 +935,27 @@ void tst_qdeclarativeecmascript::scope()
delete object;
}
+
+ {
+ QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toBool(), true);
+ QCOMPARE(object->property("test2").toBool(), true);
+
+ delete object;
+ }
+
+ {
+ QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+ }
}
/*
@@ -907,6 +976,8 @@ void tst_qdeclarativeecmascript::signalParameterTypes()
QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
+
+ delete object;
}
/*
@@ -923,6 +994,8 @@ void tst_qdeclarativeecmascript::objectsCompareAsEqual()
QCOMPARE(object->property("test3").toBool(), true);
QCOMPARE(object->property("test4").toBool(), true);
QCOMPARE(object->property("test5").toBool(), true);
+
+ delete object;
}
/*
@@ -943,6 +1016,8 @@ void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
QCOMPARE(object->property("c2").toInt(), 19);
QCOMPARE(object->property("c3").toInt(), 19);
+
+ delete object;
}
void tst_qdeclarativeecmascript::dynamicCreation_data()
@@ -972,6 +1047,8 @@ void tst_qdeclarativeecmascript::dynamicCreation()
QObject *created = object->objectProperty();
QVERIFY(created);
QCOMPARE(created->objectName(), createdName);
+
+ delete object;
}
/*
@@ -1020,6 +1097,8 @@ void tst_qdeclarativeecmascript::objectToString()
QMetaObject::invokeMethod(object, "testToString");
QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
+
+ delete object;
}
/*
@@ -1034,6 +1113,7 @@ void tst_qdeclarativeecmascript::selfDeletingBinding()
QObject *object = component.create();
QVERIFY(object != 0);
object->setProperty("triggerDelete", true);
+ delete object;
}
{
@@ -1041,6 +1121,7 @@ void tst_qdeclarativeecmascript::selfDeletingBinding()
QObject *object = component.create();
QVERIFY(object != 0);
object->setProperty("triggerDelete", true);
+ delete object;
}
}
@@ -1056,6 +1137,7 @@ void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
+ delete object;
}
/*
@@ -1091,6 +1173,8 @@ void tst_qdeclarativeecmascript::scriptErrors()
QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
emit object->thirdBasicSignal();
+
+ delete object;
}
/*
@@ -1108,6 +1192,16 @@ void tst_qdeclarativeecmascript::functionErrors()
QObject *object = component.create();
QVERIFY(object != 0);
delete object;
+
+ // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
+ QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
+ url = componentTwo.url().toString();
+ object = componentTwo.create();
+ QVERIFY(object != 0);
+ warning = url + QLatin1String(":16: TypeError: Result of expression 'scarceResourceProvider.scarceResource' [[object Object]] is not a function.");
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
+ QMetaObject::invokeMethod(object, "retrieveScarceResource");
+ delete object;
}
/*
@@ -1156,6 +1250,8 @@ void tst_qdeclarativeecmascript::signalTriggeredBindings()
QCOMPARE(object->property("base").toReal(), 400.);
QCOMPARE(object->property("test1").toReal(), 400.);
QCOMPARE(object->property("test2").toReal(), 400.);
+
+ delete object;
}
/*
@@ -1171,6 +1267,8 @@ void tst_qdeclarativeecmascript::listProperties()
QCOMPARE(object->property("test2").toInt(), 2);
QCOMPARE(object->property("test3").toBool(), true);
QCOMPARE(object->property("test4").toBool(), true);
+
+ delete object;
}
void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
@@ -1192,6 +1290,8 @@ void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
object->setObjectProperty(&object2);
QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
}
void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
@@ -1204,6 +1304,7 @@ void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != 0);
+ delete object;
}
void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
@@ -1216,6 +1317,7 @@ void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != 0);
+ delete object;
}
static int transientErrorsMsgCount = 0;
@@ -1239,6 +1341,8 @@ void tst_qdeclarativeecmascript::transientErrors()
qInstallMsgHandler(old);
QCOMPARE(transientErrorsMsgCount, 0);
+
+ delete object;
}
// One binding erroring multiple times, but then resolving
@@ -1254,6 +1358,8 @@ void tst_qdeclarativeecmascript::transientErrors()
qInstallMsgHandler(old);
QCOMPARE(transientErrorsMsgCount, 0);
+
+ delete object;
}
}
@@ -1369,6 +1475,8 @@ void tst_qdeclarativeecmascript::dynamicCreationCrash()
QMetaObject::invokeMethod(object, "dontCrash");
QObject *created = object->objectProperty();
QVERIFY(created == 0);
+
+ delete object;
}
//QTBUG-9367
@@ -1378,6 +1486,7 @@ void tst_qdeclarativeecmascript::regExpBug()
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
+ delete object;
}
void tst_qdeclarativeecmascript::callQtInvokables()
@@ -2151,6 +2260,8 @@ void tst_qdeclarativeecmascript::ownership()
delete object;
}
+
+ delete context;
}
class CppOwnershipReturnValue : public QObject
@@ -2269,6 +2380,7 @@ void tst_qdeclarativeecmascript::qlistqobjectMethods()
QCOMPARE(object->property("test2").toBool(), true);
delete object;
+ delete context;
}
// QTBUG-9205
@@ -2389,6 +2501,285 @@ void tst_qdeclarativeecmascript::signalWithUnknownTypes()
delete object;
}
+void tst_qdeclarativeecmascript::moduleApi()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("existingUriTest").toInt(), 20);
+ QCOMPARE(object->property("scriptTest").toInt(), 13);
+ QCOMPARE(object->property("qobjectTest").toInt(), 20);
+ QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
+ QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
+ QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
+ delete object;
+
+ // test that caching of module apis works correctly.
+ QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
+ object = componentTwo.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("existingUriTest").toInt(), 20);
+ QCOMPARE(object->property("scriptTest").toInt(), 13); // shouldn't have incremented.
+ QCOMPARE(object->property("qobjectParentedTest").toInt(), 26); // shouldn't have incremented.
+ delete object;
+
+ // test that writing to a property of module apis works correctly.
+ QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
+ QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
+ QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
+ object = componentThree.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
+ QCOMPARE(object->property("writableProperty").toInt(), 50);
+ QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
+ QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
+ QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
+ QCOMPARE(object->property("writableProperty").toInt(), 30);
+ delete object;
+
+ QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
+ QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
+ object = failOne.create();
+ QVERIFY(object == 0); // should have failed: invalid major version
+
+ QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
+ QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
+ object = failTwo.create();
+ QVERIFY(object == 0); // should have failed: invalid minor version
+}
+
+void tst_qdeclarativeecmascript::importScripts()
+{
+ QObject *object = 0;
+
+ // first, ensure that the required behaviour works.
+ QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
+ object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
+ QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
+ QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
+ QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
+ delete object;
+
+ QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
+ object = componentTwo.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("componentError"), QVariant(5));
+ delete object;
+
+ // then, ensure that unintended behaviour does not work.
+ QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
+ QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Result of expression 'TestScriptImport.ImportOneJs' [undefined] is not an object.");
+ QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
+ object = failOneComponent.create();
+ QVERIFY(object != 0);
+ QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
+ delete object;
+ QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
+ expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
+ QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
+ object = failTwoComponent.create();
+ QVERIFY(object != 0);
+ QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
+ delete object;
+ QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
+ expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Result of expression 'testQtObject.TestModuleImport.JsQtTest' [undefined] is not an object.");
+ QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
+ object = failThreeComponent.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
+ delete object;
+ QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
+ expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
+ QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
+ object = failFourComponent.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
+ delete object;
+ QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
+ expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
+ QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
+ expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
+ QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
+ object = failFiveComponent.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("componentError"), QVariant(0));
+ delete object;
+
+ // also, test that importing scripts with .pragma library works as required
+ QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
+ object = pragmaLibraryComponent.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("testValue"), QVariant(31));
+ delete object;
+
+ // and that .pragma library scripts don't inherit imports from any .qml file
+ QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
+ object = pragmaLibraryComponentTwo.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("testValue"), QVariant(0));
+ delete object;
+}
+
+void tst_qdeclarativeecmascript::scarceResources()
+{
+ QPixmap origPixmap(100, 100);
+ origPixmap.fill(Qt::blue);
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
+ ScarceResourceObject *eo = 0;
+ QObject *object = 0;
+
+ // in the following three cases, the instance created from the component
+ // has a property which is a copy of the scarce resource; hence, the
+ // resource should NOT be detached prior to deletion of the object instance,
+ // unless the resource is destroyed explicitly.
+ QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
+ object = component.create();
+ QVERIFY(object != 0);
+ QVERIFY(object->property("scarceResourceCopy").isValid());
+ QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+ QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
+ delete object;
+
+ QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
+ object = componentTwo.create();
+ QVERIFY(object != 0);
+ QVERIFY(object->property("scarceResourceCopy").isValid());
+ QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+ QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
+ delete object;
+
+ QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
+ object = componentThree.create();
+ QVERIFY(object != 0);
+ QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
+ QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
+ delete object;
+
+ // in the following three cases, no other copy should exist in memory,
+ // and so it should be detached (unless explicitly preserved).
+ QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
+ object = componentFour.create();
+ QVERIFY(object != 0);
+ QVERIFY(object->property("scarceResourceTest").isValid());
+ QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
+ QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
+ delete object;
+
+ QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
+ object = componentFive.create();
+ QVERIFY(object != 0);
+ QVERIFY(object->property("scarceResourceTest").isValid());
+ QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
+ QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
+ delete object;
+
+ QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
+ object = componentSix.create();
+ QVERIFY(object != 0);
+ QVERIFY(object->property("scarceResourceTest").isValid());
+ QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
+ QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
+ delete object;
+
+ // test that scarce resources are handled correctly for imports
+ QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
+ object = componentSeven.create();
+ QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
+ QVERIFY(ep->scarceResources == 0); // but they should have been released by this point.
+ delete object;
+
+ QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
+ object = componentEight.create();
+ QVERIFY(object != 0);
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
+ QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ delete object;
+
+ QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
+ object = componentNine.create();
+ QVERIFY(object != 0);
+ QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
+ QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+ QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
+ QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
+ QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
+ QVERIFY(ep->scarceResources == 0); // this will still be zero, because "preserve()" REMOVES it from this list.
+ delete object;
+
+ // test that scarce resources are handled properly in signal invocation
+ QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
+ object = componentTen.create();
+ QVERIFY(object != 0);
+ QObject *srsc = object->findChild<QObject*>("srsc");
+ QVERIFY(srsc);
+ QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
+ QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QMetaObject::invokeMethod(srsc, "testSignal");
+ QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
+ QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
+ QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
+ QVERIFY(srsc->property("scarceResourceCopy").isValid());
+ QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
+ QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ delete object;
+
+ // test that scarce resources are handled properly from js functions in qml files
+ QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
+ object = componentEleven.create();
+ QVERIFY(object != 0);
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QMetaObject::invokeMethod(object, "retrieveScarceResource");
+ QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
+ QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
+ QMetaObject::invokeMethod(object, "releaseScarceResource");
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ delete object;
+
+ // test that if an exception occurs while invoking js function from cpp, that the resources are released.
+ QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
+ object = componentTwelve.create();
+ QVERIFY(object != 0);
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QString expectedWarning = QLatin1String("file://") + TEST_FILE("scarceresources/scarceResourceFunctionFail.qml").toLocalFile() + QLatin1String(":16: TypeError: Result of expression 'scarceResourceProvider.scarceResource' [[object Object]] is not a function.");
+ QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData()); // we expect a meaningful warning to be printed.
+ QMetaObject::invokeMethod(object, "retrieveScarceResource");
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ delete object;
+}
+
// Test that assigning a null object works
// Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
void tst_qdeclarativeecmascript::nullObjectBinding()
@@ -2970,6 +3361,7 @@ void tst_qdeclarativeecmascript::revisionErrors()
QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
QVERIFY(object != 0);
+ delete object;
}
{
QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
@@ -2991,6 +3383,7 @@ void tst_qdeclarativeecmascript::revisionErrors()
QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
QVERIFY(object != 0);
+ delete object;
}
{
QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
@@ -3006,6 +3399,7 @@ void tst_qdeclarativeecmascript::revisionErrors()
QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
QVERIFY(object != 0);
+ delete object;
}
}
@@ -3017,6 +3411,7 @@ void tst_qdeclarativeecmascript::revision()
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
QVERIFY(object != 0);
+ delete object;
}
{
QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
@@ -3024,6 +3419,7 @@ void tst_qdeclarativeecmascript::revision()
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
QVERIFY(object != 0);
+ delete object;
}
{
QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
@@ -3031,6 +3427,7 @@ void tst_qdeclarativeecmascript::revision()
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
QVERIFY(object != 0);
+ delete object;
}
// Test that non-root classes can resolve revisioned methods
{
@@ -3081,6 +3478,18 @@ void tst_qdeclarativeecmascript::pushCleanContext()
QCOMPARE(func2.call().toInt32(), 6);
}
+void tst_qdeclarativeecmascript::realToInt()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+
+ QMetaObject::invokeMethod(object, "test1");
+ QCOMPARE(object->value(), int(4));
+ QMetaObject::invokeMethod(object, "test2");
+ QCOMPARE(object->value(), int(8));
+}
+
QTEST_MAIN(tst_qdeclarativeecmascript)
#include "tst_qdeclarativeecmascript.moc"
diff --git a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp
index c8e7817adc..dba12599f9 100644
--- a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp
+++ b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp
@@ -863,6 +863,8 @@ void tst_QDeclarativeGridView::noCurrentIndex()
QCOMPARE(gridview->currentIndex(), 5);
QVERIFY(gridview->currentItem());
QVERIFY(gridview->highlightItem());
+
+ delete canvas;
}
void tst_QDeclarativeGridView::changeFlow()
@@ -1621,6 +1623,8 @@ void tst_QDeclarativeGridView::resetModel()
QTRY_VERIFY(display != 0);
QTRY_COMPARE(display->text(), strings.at(i));
}
+
+ delete canvas;
}
void tst_QDeclarativeGridView::enforceRange()
@@ -1748,6 +1752,8 @@ void tst_QDeclarativeGridView::QTBUG_8456()
QTRY_VERIFY(gridview != 0);
QTRY_COMPARE(gridview->currentIndex(), 0);
+
+ delete canvas;
}
void tst_QDeclarativeGridView::manualHighlight()
@@ -1792,6 +1798,8 @@ void tst_QDeclarativeGridView::manualHighlight()
QTRY_COMPARE(gridview->currentItem(), findItem<QDeclarativeItem>(contentItem, "wrapper", 0));
QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
+
+ delete canvas;
}
void tst_QDeclarativeGridView::footer()
@@ -1839,6 +1847,8 @@ void tst_QDeclarativeGridView::footer()
QCOMPARE(footer->y(), 600.0);
QCOMPARE(footer->height(), 20.0);
QCOMPARE(gridview->contentY(), 0.0);
+
+ delete canvas;
}
void tst_QDeclarativeGridView::header()
@@ -1888,6 +1898,8 @@ void tst_QDeclarativeGridView::header()
QCOMPARE(header->y(), 10.0);
QCOMPARE(header->height(), 20.0);
QCOMPARE(gridview->contentY(), 10.0);
+
+ delete canvas;
}
void tst_QDeclarativeGridView::indexAt()
diff --git a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp
index 87e33474d3..26854ef9a4 100644
--- a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp
+++ b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp
@@ -224,6 +224,8 @@ void tst_qdeclarativeimage::clearSource()
QCOMPARE(obj->width(), 0.);
QCOMPARE(obj->height(), 0.);
QCOMPARE(obj->progress(), 0.0);
+
+ delete obj;
}
void tst_qdeclarativeimage::resized()
@@ -531,6 +533,8 @@ void tst_qdeclarativeimage::tiling_QTBUG_6716()
}
}
}
+
+ delete canvas;
}
void tst_qdeclarativeimage::noLoading()
@@ -579,6 +583,8 @@ void tst_qdeclarativeimage::noLoading()
QTRY_COMPARE(sourceSpy.count(), 4);
QTRY_COMPARE(progressSpy.count(), 2);
QTRY_COMPARE(statusSpy.count(), 2);
+
+ delete obj;
}
void tst_qdeclarativeimage::paintedWidthHeight()
@@ -648,6 +654,8 @@ void tst_qdeclarativeimage::sourceSize_QTBUG_14303()
QTRY_COMPARE(obj->sourceSize().width(), 200);
QTRY_COMPARE(obj->sourceSize().height(), 200);
QTRY_COMPARE(sourceSizeSpy.count(), 2);
+
+ delete obj;
}
void tst_qdeclarativeimage::sourceSize_QTBUG_16389()
diff --git a/tests/auto/declarative/qdeclarativeinfo/data/NestedComponent.qml b/tests/auto/declarative/qdeclarativeinfo/data/NestedComponent.qml
new file mode 100644
index 0000000000..d8ae8ae3ba
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeinfo/data/NestedComponent.qml
@@ -0,0 +1,23 @@
+import QtQuick 1.0
+
+QtObject {
+ property variant nested
+ property variant nested2: nested.nested
+
+ property variant component
+ component: Component {
+ id: myComponent
+ NestedObject { property string testProp: "test" }
+ }
+
+ property variant component2
+ component2: Component {
+ id: myComponent2
+ Image { property string testProp: "test" }
+ }
+
+ Component.onCompleted: {
+ nested = myComponent.createObject(0);
+ nested2 = myComponent2.createObject(0);
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativeinfo/tst_qdeclarativeinfo.cpp b/tests/auto/declarative/qdeclarativeinfo/tst_qdeclarativeinfo.cpp
index 42459f10a4..e02ab2d8ca 100644
--- a/tests/auto/declarative/qdeclarativeinfo/tst_qdeclarativeinfo.cpp
+++ b/tests/auto/declarative/qdeclarativeinfo/tst_qdeclarativeinfo.cpp
@@ -60,6 +60,7 @@ public:
private slots:
void qmlObject();
void nestedQmlObject();
+ void nestedComponent();
void nonQmlObject();
void nullObject();
void nonQmlContextedObject();
@@ -82,7 +83,7 @@ void tst_qdeclarativeinfo::qmlObject()
QObject *object = component.create();
QVERIFY(object != 0);
- QString message = component.url().toString() + ":3:1: QML QObject_QML_0: Test Message";
+ QString message = component.url().toString() + ":3:1: QML QtObject: Test Message";
QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
qmlInfo(object) << "Test Message";
@@ -115,6 +116,27 @@ void tst_qdeclarativeinfo::nestedQmlObject()
qmlInfo(nested2) << "Inner Object";
}
+void tst_qdeclarativeinfo::nestedComponent()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("NestedComponent.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QObject *nested = qvariant_cast<QObject *>(object->property("nested"));
+ QVERIFY(nested != 0);
+ QObject *nested2 = qvariant_cast<QObject *>(object->property("nested2"));
+ QVERIFY(nested2 != 0);
+
+ QString message = component.url().toString() + ":10:9: QML NestedObject: Complex Object";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
+ qmlInfo(nested) << "Complex Object";
+
+ message = component.url().toString() + ":16:9: QML Image: Simple Object";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
+ qmlInfo(nested2) << "Simple Object";
+}
+
void tst_qdeclarativeinfo::nonQmlObject()
{
QObject object;
diff --git a/tests/auto/declarative/qdeclarativeitem/data/keynavigationtest_implicit.qml b/tests/auto/declarative/qdeclarativeitem/data/keynavigationtest_implicit.qml
new file mode 100644
index 0000000000..52ffaea0ec
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeitem/data/keynavigationtest_implicit.qml
@@ -0,0 +1,68 @@
+import QtQuick 1.0
+
+Grid {
+ columns: 2
+ width: 100; height: 100
+ function verify() {
+ if (item1.KeyNavigation.tab != item2)
+ return false;
+ if (item1.KeyNavigation.backtab != item4)
+ return false;
+
+ if (item2.KeyNavigation.left != item1)
+ return false;
+ if (item2.KeyNavigation.down != item4)
+ return false;
+ if (item2.KeyNavigation.tab != item3)
+ return false;
+ if (item2.KeyNavigation.backtab != item1)
+ return false;
+
+ if (item3.KeyNavigation.right != item4)
+ return false;
+ if (item3.KeyNavigation.up != item1)
+ return false;
+ if (item3.KeyNavigation.tab != item4)
+ return false;
+ if (item3.KeyNavigation.backtab != item2)
+ return false;
+
+ return true;
+ }
+
+ Rectangle {
+ id: item1
+ objectName: "item1"
+ focus: true
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.tab: item2
+ KeyNavigation.backtab: item4
+ }
+ Rectangle {
+ id: item2
+ objectName: "item2"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.left: item1
+ KeyNavigation.down: item4
+ KeyNavigation.tab: item3
+ KeyNavigation.backtab: item1
+ }
+ Rectangle {
+ id: item3
+ objectName: "item3"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.right: item4
+ KeyNavigation.up: item1
+ KeyNavigation.tab: item4
+ KeyNavigation.backtab: item2
+ }
+ Rectangle {
+ id: item4
+ objectName: "item4"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp b/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp
index 52c9a726ff..7d0a35be23 100644
--- a/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp
+++ b/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp
@@ -67,6 +67,7 @@ private slots:
void keyNavigation();
void keyNavigation_RightToLeft();
void keyNavigation_skipNotVisible();
+ void keyNavigation_implicitSetting();
void layoutMirroring();
void layoutMirroringIllegalParent();
void smooth();
@@ -773,6 +774,131 @@ void tst_QDeclarativeItem::keyNavigation_skipNotVisible()
delete canvas;
}
+void tst_QDeclarativeItem::keyNavigation_implicitSetting()
+{
+ QDeclarativeView *canvas = new QDeclarativeView(0);
+ canvas->setFixedSize(240,320);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/keynavigationtest_implicit.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QEvent wa(QEvent::WindowActivate);
+ QApplication::sendEvent(canvas, &wa);
+ QFocusEvent fe(QEvent::FocusIn);
+ QApplication::sendEvent(canvas, &fe);
+
+ QDeclarativeItem *item = findItem<QDeclarativeItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ QVariant result;
+ QVERIFY(QMetaObject::invokeMethod(canvas->rootObject(), "verify",
+ Q_RETURN_ARG(QVariant, result)));
+ QVERIFY(result.toBool());
+
+ // right
+ QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // back to item1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // down
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item3");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // move to item4
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item4");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // left
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item3");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // back to item4
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item4");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // up
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // back to item4
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item4");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // tab
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // back to item4
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item4");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // backtab
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QDeclarativeItem>(canvas->rootObject(), "item3");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ delete canvas;
+}
+
void tst_QDeclarativeItem::smooth()
{
QDeclarativeComponent component(&engine);
@@ -1092,6 +1218,7 @@ void tst_QDeclarativeItem::childrenRect()
QCOMPARE(item->height(), qreal(0));
delete o;
+ delete canvas;
}
// QTBUG-11383
diff --git a/tests/auto/declarative/qdeclarativelanguage/data/wrongType.17.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/wrongType.17.errors.txt
new file mode 100644
index 0000000000..ef34d0ea95
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativelanguage/data/wrongType.17.errors.txt
@@ -0,0 +1 @@
+3:19:Invalid property assignment: unknown enumeration
diff --git a/tests/auto/declarative/qdeclarativelanguage/data/wrongType.17.qml b/tests/auto/declarative/qdeclarativelanguage/data/wrongType.17.qml
new file mode 100644
index 0000000000..f678fb3136
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativelanguage/data/wrongType.17.qml
@@ -0,0 +1,5 @@
+import Test 1.0
+MyTypeObject {
+ enumProperty: 6
+}
+
diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
index 2ce493bd2a..42a02ed720 100644
--- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
+++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
@@ -273,6 +273,7 @@ void tst_qdeclarativelanguage::errors_data()
QTest::newRow("wrongType (int for string)") << "wrongType.14.qml" << "wrongType.14.errors.txt" << false;
QTest::newRow("wrongType (int for url)") << "wrongType.15.qml" << "wrongType.15.errors.txt" << false;
QTest::newRow("wrongType (invalid object)") << "wrongType.16.qml" << "wrongType.16.errors.txt" << false;
+ QTest::newRow("wrongType (int for enum)") << "wrongType.17.qml" << "wrongType.17.errors.txt" << false;
QTest::newRow("readOnly.1") << "readOnly.1.qml" << "readOnly.1.errors.txt" << false;
QTest::newRow("readOnly.2") << "readOnly.2.qml" << "readOnly.2.errors.txt" << false;
diff --git a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp
index 2f7513f09e..cf053e5fb0 100644
--- a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp
+++ b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp
@@ -754,6 +754,8 @@ void tst_qdeclarativelistmodel::get()
QCOMPARE(spyResult.at(0).toInt(), index);
QCOMPARE(spyResult.at(1).toInt(), 1); // only 1 item is modified at a time
QCOMPARE(spyResult.at(2).value<QList<int> >(), (QList<int>() << role));
+
+ delete model;
}
void tst_qdeclarativelistmodel::get_data()
@@ -913,6 +915,8 @@ void tst_qdeclarativelistmodel::get_nested()
QCOMPARE(spyResult.at(1).toInt(), 1); // only 1 item is modified at a time
QCOMPARE(spyResult.at(2).value<QList<int> >(), (QList<int>() << role));
}
+
+ delete model;
}
void tst_qdeclarativelistmodel::get_nested_data()
@@ -933,6 +937,8 @@ void tst_qdeclarativelistmodel::crash_model_with_multiple_roles()
// used to cause a crash in QDeclarativeVisualDataModel
model->setProperty(0, "black", true);
+
+ delete rootItem;
}
//QTBUG-15190
@@ -944,6 +950,8 @@ void tst_qdeclarativelistmodel::set_model_cache()
QVERIFY2(component.errorString().isEmpty(), QTest::toString(component.errorString()));
QVERIFY(model != 0);
QVERIFY(model->property("ok").toBool());
+
+ delete model;
}
void tst_qdeclarativelistmodel::property_changes()
diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp
index 0c96587b30..58d999e020 100644
--- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp
+++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp
@@ -434,6 +434,7 @@ void tst_QDeclarativeListView::items()
QTRY_COMPARE(listview->highlightMoveSpeed(), 1000.0);
delete canvas;
+ delete testObject;
}
@@ -471,6 +472,7 @@ void tst_QDeclarativeListView::changed()
QTRY_COMPARE(number->text(), model.number(1));
delete canvas;
+ delete testObject;
}
template <class T>
@@ -555,6 +557,7 @@ void tst_QDeclarativeListView::inserted()
// QTRY_COMPARE(listview->contentItemHeight(), model.count() * 20.0);
delete canvas;
+ delete testObject;
}
template <class T>
@@ -712,6 +715,7 @@ void tst_QDeclarativeListView::removed(bool animated)
QCOMPARE(name->text(), QString("New"));
delete canvas;
+ delete testObject;
}
template <class T>
@@ -752,6 +756,7 @@ void tst_QDeclarativeListView::clear()
QVERIFY(listview->currentIndex() == 0);
delete canvas;
+ delete testObject;
}
@@ -841,6 +846,7 @@ void tst_QDeclarativeListView::moved()
}
delete canvas;
+ delete testObject;
}
void tst_QDeclarativeListView::enforceRange()
@@ -951,6 +957,7 @@ void tst_QDeclarativeListView::spacing()
}
delete canvas;
+ delete testObject;
}
void tst_QDeclarativeListView::sections()
@@ -1288,6 +1295,8 @@ void tst_QDeclarativeListView::noCurrentIndex()
QCOMPARE(listview->currentIndex(), 2);
QVERIFY(listview->highlightItem());
QVERIFY(listview->currentItem());
+
+ delete canvas;
}
void tst_QDeclarativeListView::itemList()
@@ -1381,6 +1390,7 @@ void tst_QDeclarativeListView::cacheBuffer()
}
delete canvas;
+ delete testObject;
}
void tst_QDeclarativeListView::positionViewAtIndex()
@@ -1540,6 +1550,7 @@ void tst_QDeclarativeListView::positionViewAtIndex()
QTRY_COMPARE(listview->contentY(), 510.);
delete canvas;
+ delete testObject;
}
void tst_QDeclarativeListView::resetModel()
@@ -1844,6 +1855,7 @@ void tst_QDeclarativeListView::QTBUG_11105()
QCOMPARE(itemCount, 5);
delete canvas;
+ delete testObject;
}
void tst_QDeclarativeListView::header()
@@ -2116,6 +2128,7 @@ void tst_QDeclarativeListView::resizeView()
QCOMPARE(heightRatio.toReal(), 0.25);
delete canvas;
+ delete testObject;
}
void tst_QDeclarativeListView::sizeLessThan1()
@@ -2151,6 +2164,7 @@ void tst_QDeclarativeListView::sizeLessThan1()
}
delete canvas;
+ delete testObject;
}
void tst_QDeclarativeListView::QTBUG_14821()
@@ -2299,6 +2313,7 @@ void tst_QDeclarativeListView::indexAt()
QCOMPARE(listview->indexAt(240,20), -1);
delete canvas;
+ delete testObject;
}
void tst_QDeclarativeListView::incrementalModel()
diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit1/qmldir b/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit1/qmldir
new file mode 100644
index 0000000000..7f5b3a362d
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit1/qmldir
@@ -0,0 +1,2 @@
+plugin AType
+
diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit1/temptest.qml b/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit1/temptest.qml
new file mode 100644
index 0000000000..a45ac2dd8c
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit1/temptest.qml
@@ -0,0 +1,14 @@
+import QtQuick 1.0
+
+// this qml file uses a type which is meant to be defined
+// in a plugin which is specified in the qmldir file.
+// however, that plugin doesn't exist, so it cannot be
+// loaded, and hence the AItem type will be an unknown type.
+
+Item {
+ id: root
+
+ AItem {
+ id: unknown
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativedom/data/MyComponent.qml b/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/Test.qml
index f6760b6a9f..83c65538ba 100644
--- a/tests/auto/declarative/qdeclarativedom/data/MyComponent.qml
+++ b/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/Test.qml
@@ -1,4 +1,5 @@
import QtQuick 1.0
Item {
+ id: moduleRoot
}
diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/qmldir b/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/qmldir
new file mode 100644
index 0000000000..7c4def92fc
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/qmldir
@@ -0,0 +1,3 @@
+foo bar foo bar
+internal foo bar foo
+Test 1.0 Test.qml
diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/temptest2.qml b/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/temptest2.qml
new file mode 100644
index 0000000000..3eb29f43da
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativemoduleplugin/data/implicit2/temptest2.qml
@@ -0,0 +1,8 @@
+import QtQuick 1.0
+
+// the type loader will implicitly search "." for a qmldir
+// and the qmldir has various syntax errors in it.
+
+Item {
+ id: root
+}
diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.cpp b/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.cpp
index 9d1c609616..06b65d3c6f 100644
--- a/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.cpp
+++ b/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.cpp
@@ -70,6 +70,7 @@ private slots:
void remoteImportWithUnquotedUri();
void versionNotInstalled();
void versionNotInstalled_data();
+ void implicitQmldir();
};
#ifdef Q_OS_SYMBIAN
@@ -119,7 +120,6 @@ inline QUrl TEST_FILE(const QString &filename)
return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath(filename));
}
-
void tst_qdeclarativemoduleplugin::importsPlugin()
{
QDeclarativeEngine engine;
@@ -308,6 +308,53 @@ void tst_qdeclarativemoduleplugin::versionNotInstalled()
VERIFY_ERRORS(errorFile.toLatin1().constData());
}
+
+// test that errors are reporting correctly for plugin loading and qmldir parsing
+void tst_qdeclarativemoduleplugin::implicitQmldir()
+{
+ QDeclarativeEngine engine;
+
+ QObject *obj = 0;
+ QList<QDeclarativeError> errors;
+ QString qmldirUrl;
+ QStringList expectedErrors;
+
+ // parsing qmldir succeeds, but plugin specified in the qmldir file doesn't exist
+ QDeclarativeComponent c(&engine, TEST_FILE("data/implicit1/temptest.qml"));
+ qmldirUrl = TEST_FILE("data/implicit1/qmldir").toString();
+ errors = c.errors();
+ QString moduleName = TEST_FILE("data/implicit1").toString().remove(0,7).replace(QLatin1String("/"), QLatin1String("."));
+ expectedErrors << QString(QLatin1String(": module \"") + moduleName + QLatin1String("\" plugin \"AType\" not found"));
+ QVERIFY(errors.size() == expectedErrors.size());
+ for (int i = 0; i < errors.size(); ++i) {
+ QString msg = qmldirUrl + expectedErrors.at(i);
+ QCOMPARE(errors.at(i).toString(), msg); // ensure that the expected message matches the real message.
+ }
+ QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
+ obj = c.create();
+ QVERIFY(!obj);
+ delete obj;
+
+ // parsing qmldir fails due to syntax errors etc.
+ QDeclarativeComponent c2(&engine, TEST_FILE("data/implicit2/temptest2.qml"));
+ qmldirUrl = TEST_FILE("data/implicit2/qmldir").toString();
+ errors = c2.errors();
+ expectedErrors = QStringList();
+ expectedErrors << QLatin1String(":1:12: unexpected token");
+ expectedErrors << QLatin1String(":1: expected '.'");
+ expectedErrors << QLatin1String(":2:17: unexpected token");
+ QVERIFY(errors.size() == expectedErrors.size());
+ for (int i = 0; i < errors.size(); ++i) {
+ QString msg = qmldirUrl + expectedErrors.at(i);
+ QCOMPARE(errors.at(i).toString(), msg); // ensure that the expected message matches the real message.
+ }
+ QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
+ obj = c2.create();
+ QVERIFY(!obj);
+ delete obj;
+}
+
+
QTEST_MAIN(tst_qdeclarativemoduleplugin)
#include "tst_qdeclarativemoduleplugin.moc"
diff --git a/tests/auto/declarative/qdeclarativeparticles/tst_qdeclarativeparticles.cpp b/tests/auto/declarative/qdeclarativeparticles/tst_qdeclarativeparticles.cpp
index 6e90cd84ab..31d566fa15 100644
--- a/tests/auto/declarative/qdeclarativeparticles/tst_qdeclarativeparticles.cpp
+++ b/tests/auto/declarative/qdeclarativeparticles/tst_qdeclarativeparticles.cpp
@@ -105,6 +105,8 @@ void tst_QDeclarativeParticles::properties()
particles->setProperty("emissionRate", 12);
QCOMPARE(particles->property("emissionRate").toInt(), 12);
+
+ delete canvas;
}
void tst_QDeclarativeParticles::motionGravity()
@@ -145,6 +147,8 @@ void tst_QDeclarativeParticles::motionGravity()
QCOMPARE(xattractorSpy.count(), 1);
QCOMPARE(yattractorSpy.count(), 1);
QCOMPARE(accelerationSpy.count(), 1);
+
+ delete canvas;
}
void tst_QDeclarativeParticles::motionWander()
@@ -193,6 +197,8 @@ void tst_QDeclarativeParticles::motionWander()
QCOMPARE(xvarianceSpy.count(), 1);
QCOMPARE(yvarianceSpy.count(), 1);
QCOMPARE(paceSpy.count(), 1);
+
+ delete canvas;
}
void tst_QDeclarativeParticles::runs()
@@ -203,6 +209,8 @@ void tst_QDeclarativeParticles::runs()
QObject* particles = canvas->rootObject()->findChild<QObject*>("particles");
QVERIFY(particles);
QTest::qWait(1000);//Run for one second. Test passes if it doesn't crash.
+
+ delete canvas;
}
QDeclarativeView *tst_QDeclarativeParticles::createView(const QString &filename)
diff --git a/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp b/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp
index 46c351985f..fa6093f311 100644
--- a/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp
+++ b/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp
@@ -469,6 +469,7 @@ void tst_QDeclarativePathView::dataModel()
QTRY_COMPARE(pathview->offset(), 2.);
delete canvas;
+ delete testObject;
}
void tst_QDeclarativePathView::pathMoved()
@@ -628,6 +629,8 @@ void tst_QDeclarativePathView::resetModel()
QVERIFY(display != 0);
QCOMPARE(display->text(), strings.at(i));
}
+
+ delete canvas;
}
void tst_QDeclarativePathView::propertyChanges()
diff --git a/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp b/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp
index edb182cdec..725d0238bc 100644
--- a/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp
+++ b/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp
@@ -289,18 +289,19 @@ void tst_qdeclarativepixmapcache::parallel()
void tst_qdeclarativepixmapcache::massive()
{
+ QDeclarativeEngine engine;
QUrl url = thisfile.resolved(QUrl("data/massive.png"));
// Confirm that massive images remain in the cache while they are
// in use by the application.
{
qint64 cachekey = 0;
- QDeclarativePixmap p(0, url);
+ QDeclarativePixmap p(&engine, url);
QVERIFY(p.isReady());
QVERIFY(p.pixmap().size() == QSize(10000, 1000));
cachekey = p.pixmap().cacheKey();
- QDeclarativePixmap p2(0, url);
+ QDeclarativePixmap p2(&engine, url);
QVERIFY(p2.isReady());
QVERIFY(p2.pixmap().size() == QSize(10000, 1000));
@@ -312,13 +313,13 @@ void tst_qdeclarativepixmapcache::massive()
{
qint64 cachekey = 0;
{
- QDeclarativePixmap p(0, url);
+ QDeclarativePixmap p(&engine, url);
QVERIFY(p.isReady());
QVERIFY(p.pixmap().size() == QSize(10000, 1000));
cachekey = p.pixmap().cacheKey();
}
- QDeclarativePixmap p2(0, url);
+ QDeclarativePixmap p2(&engine, url);
QVERIFY(p2.isReady());
QVERIFY(p2.pixmap().size() == QSize(10000, 1000));
diff --git a/tests/auto/declarative/qdeclarativepositioners/tst_qdeclarativepositioners.cpp b/tests/auto/declarative/qdeclarativepositioners/tst_qdeclarativepositioners.cpp
index 78821cb3d3..f1d17d5cb3 100644
--- a/tests/auto/declarative/qdeclarativepositioners/tst_qdeclarativepositioners.cpp
+++ b/tests/auto/declarative/qdeclarativepositioners/tst_qdeclarativepositioners.cpp
@@ -1106,80 +1106,94 @@ void tst_QDeclarativePositioners::test_conflictinganchors()
QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QVERIFY(warningMessage.isEmpty());
+ delete item;
component.setData("import QtQuick 1.0\nRow { Item {} }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QVERIFY(warningMessage.isEmpty());
+ delete item;
component.setData("import QtQuick 1.0\nGrid { Item {} }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QVERIFY(warningMessage.isEmpty());
+ delete item;
component.setData("import QtQuick 1.0\nFlow { Item {} }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QVERIFY(warningMessage.isEmpty());
+ delete item;
component.setData("import QtQuick 1.0\nColumn { Item { anchors.top: parent.top } }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QCOMPARE(warningMessage, QString("file::2:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column"));
warningMessage.clear();
+ delete item;
component.setData("import QtQuick 1.0\nColumn { Item { anchors.centerIn: parent } }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QCOMPARE(warningMessage, QString("file::2:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column"));
warningMessage.clear();
+ delete item;
component.setData("import QtQuick 1.0\nColumn { Item { anchors.left: parent.left } }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QVERIFY(warningMessage.isEmpty());
warningMessage.clear();
+ delete item;
component.setData("import QtQuick 1.0\nRow { Item { anchors.left: parent.left } }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QCOMPARE(warningMessage, QString("file::2:1: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row"));
warningMessage.clear();
+ delete item;
component.setData("import QtQuick 1.0\nRow { Item { anchors.fill: parent } }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QCOMPARE(warningMessage, QString("file::2:1: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row"));
warningMessage.clear();
+ delete item;
component.setData("import QtQuick 1.0\nRow { Item { anchors.top: parent.top } }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QVERIFY(warningMessage.isEmpty());
warningMessage.clear();
+ delete item;
component.setData("import QtQuick 1.0\nGrid { Item { anchors.horizontalCenter: parent.horizontalCenter } }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QCOMPARE(warningMessage, QString("file::2:1: QML Grid: Cannot specify anchors for items inside Grid"));
warningMessage.clear();
+ delete item;
component.setData("import QtQuick 1.0\nGrid { Item { anchors.centerIn: parent } }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QCOMPARE(warningMessage, QString("file::2:1: QML Grid: Cannot specify anchors for items inside Grid"));
warningMessage.clear();
+ delete item;
component.setData("import QtQuick 1.0\nFlow { Item { anchors.verticalCenter: parent.verticalCenter } }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QCOMPARE(warningMessage, QString("file::2:1: QML Flow: Cannot specify anchors for items inside Flow"));
+ delete item;
component.setData("import QtQuick 1.0\nFlow { Item { anchors.fill: parent } }", QUrl::fromLocalFile(""));
item = qobject_cast<QDeclarativeItem*>(component.create());
QVERIFY(item);
QCOMPARE(warningMessage, QString("file::2:1: QML Flow: Cannot specify anchors for items inside Flow"));
qInstallMsgHandler(oldMsgHandler);
+ delete item;
}
void tst_QDeclarativePositioners::test_vertical_qgraphicswidget()
diff --git a/tests/auto/declarative/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp b/tests/auto/declarative/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp
index 5b225892c5..d5f2396c6e 100644
--- a/tests/auto/declarative/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp
+++ b/tests/auto/declarative/qdeclarativesmoothedanimation/tst_qdeclarativesmoothedanimation.cpp
@@ -177,6 +177,8 @@ void tst_qdeclarativesmoothedanimation::valueSource()
QTRY_COMPARE(theRect->x(), qreal(200));
QTRY_COMPARE(theRect->y(), qreal(200));
+
+ delete rect;
}
void tst_qdeclarativesmoothedanimation::behavior()
@@ -205,6 +207,8 @@ void tst_qdeclarativesmoothedanimation::behavior()
QTRY_COMPARE(theRect->x(), qreal(200));
QTRY_COMPARE(theRect->y(), qreal(200));
+
+ delete rect;
}
QTEST_MAIN(tst_qdeclarativesmoothedanimation)
diff --git a/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp b/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp
index 557603f1f7..eca183a491 100644
--- a/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp
+++ b/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp
@@ -216,6 +216,8 @@ void tst_qdeclarativetext::text()
QVERIFY(textObject != 0);
QCOMPARE(textObject->text(), standard.at(i));
QVERIFY(textObject->width() > 0);
+
+ delete textObject;
}
for (int i = 0; i < richText.size(); i++)
@@ -229,6 +231,8 @@ void tst_qdeclarativetext::text()
QString expected = richText.at(i);
QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
QVERIFY(textObject->width() > 0);
+
+ delete textObject;
}
}
@@ -242,6 +246,8 @@ void tst_qdeclarativetext::width()
QVERIFY(textObject != 0);
QCOMPARE(textObject->width(), 0.);
+
+ delete textObject;
}
for (int i = 0; i < standard.size(); i++)
@@ -262,6 +268,8 @@ void tst_qdeclarativetext::width()
QVERIFY(textObject->boundingRect().width() > 0);
QCOMPARE(textObject->width(), qreal(metricWidth));
QVERIFY(textObject->textFormat() == QDeclarativeText::AutoText); // setting text doesn't change format
+
+ delete textObject;
}
for (int i = 0; i < richText.size(); i++)
@@ -282,6 +290,8 @@ void tst_qdeclarativetext::width()
QVERIFY(textObject != 0);
QCOMPARE(textObject->width(), qreal(documentWidth));
QVERIFY(textObject->textFormat() == QDeclarativeText::AutoText); // setting text doesn't change format
+
+ delete textObject;
}
}
@@ -298,6 +308,8 @@ void tst_qdeclarativetext::wrap()
QVERIFY(textObject != 0);
QVERIFY(textObject->wrapMode() == QDeclarativeText::WordWrap);
QCOMPARE(textObject->width(), 300.);
+
+ delete textObject;
}
for (int i = 0; i < standard.size(); i++)
@@ -314,6 +326,8 @@ void tst_qdeclarativetext::wrap()
int oldHeight = textObject->height();
textObject->setWidth(100);
QVERIFY(textObject->height() < oldHeight);
+
+ delete textObject;
}
for (int i = 0; i < richText.size(); i++)
@@ -330,6 +344,8 @@ void tst_qdeclarativetext::wrap()
qreal oldHeight = textObject->height();
textObject->setWidth(100);
QVERIFY(textObject->height() < oldHeight);
+
+ delete textObject;
}
// richtext again with a fixed height
@@ -347,6 +363,8 @@ void tst_qdeclarativetext::wrap()
qreal oldHeight = textObject->implicitHeight();
textObject->setWidth(100);
QVERIFY(textObject->implicitHeight() < oldHeight);
+
+ delete textObject;
}
}
@@ -365,6 +383,8 @@ void tst_qdeclarativetext::elide()
QCOMPARE(textObject->elideMode(), m);
QCOMPARE(textObject->width(), 100.);
+
+ delete textObject;
}
for (int i = 0; i < standard.size(); i++)
@@ -376,6 +396,8 @@ void tst_qdeclarativetext::elide()
QCOMPARE(textObject->elideMode(), m);
QCOMPARE(textObject->width(), 100.);
+
+ delete textObject;
}
// richtext - does nothing
@@ -388,6 +410,8 @@ void tst_qdeclarativetext::elide()
QCOMPARE(textObject->elideMode(), m);
QCOMPARE(textObject->width(), 100.);
+
+ delete textObject;
}
}
@@ -408,6 +432,8 @@ void tst_qdeclarativetext::textFormat()
QVERIFY(textObject != 0);
QVERIFY(textObject->textFormat() == QDeclarativeText::RichText);
+
+ delete textObject;
}
{
QDeclarativeComponent textComponent(&engine);
@@ -416,6 +442,8 @@ void tst_qdeclarativetext::textFormat()
QVERIFY(textObject != 0);
QVERIFY(textObject->textFormat() == QDeclarativeText::PlainText);
+
+ delete textObject;
}
}
@@ -497,6 +525,8 @@ void tst_qdeclarativetext::horizontalAlignment()
QDeclarativeText *textObject = qobject_cast<QDeclarativeText*>(textComponent.create());
QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
+
+ delete textObject;
}
}
@@ -510,6 +540,8 @@ void tst_qdeclarativetext::horizontalAlignment()
QDeclarativeText *textObject = qobject_cast<QDeclarativeText*>(textComponent.create());
QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
+
+ delete textObject;
}
}
@@ -648,6 +680,8 @@ void tst_qdeclarativetext::verticalAlignment()
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
+
+ delete textObject;
}
}
@@ -662,6 +696,8 @@ void tst_qdeclarativetext::verticalAlignment()
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
+
+ delete textObject;
}
}
@@ -697,6 +733,8 @@ void tst_qdeclarativetext::font()
QCOMPARE(textObject->font().pointSize(), 40);
QCOMPARE(textObject->font().bold(), false);
QCOMPARE(textObject->font().italic(), false);
+
+ delete textObject;
}
{
@@ -708,6 +746,8 @@ void tst_qdeclarativetext::font()
QCOMPARE(textObject->font().pixelSize(), 40);
QCOMPARE(textObject->font().bold(), false);
QCOMPARE(textObject->font().italic(), false);
+
+ delete textObject;
}
{
@@ -718,6 +758,8 @@ void tst_qdeclarativetext::font()
QCOMPARE(textObject->font().bold(), true);
QCOMPARE(textObject->font().italic(), false);
+
+ delete textObject;
}
{
@@ -728,6 +770,8 @@ void tst_qdeclarativetext::font()
QCOMPARE(textObject->font().italic(), true);
QCOMPARE(textObject->font().bold(), false);
+
+ delete textObject;
}
{
@@ -739,6 +783,8 @@ void tst_qdeclarativetext::font()
QCOMPARE(textObject->font().family(), QString("Helvetica"));
QCOMPARE(textObject->font().bold(), false);
QCOMPARE(textObject->font().italic(), false);
+
+ delete textObject;
}
{
@@ -748,6 +794,8 @@ void tst_qdeclarativetext::font()
QDeclarativeText *textObject = qobject_cast<QDeclarativeText*>(textComponent.create());
QCOMPARE(textObject->font().family(), QString(""));
+
+ delete textObject;
}
}
@@ -763,6 +811,8 @@ void tst_qdeclarativetext::style()
QCOMPARE((int)textObject->style(), (int)styles.at(i));
QCOMPARE(textObject->styleColor(), QColor("white"));
+
+ delete textObject;
}
QString componentStr = "import QtQuick 1.0\nText { text: \"Hello World\" }";
QDeclarativeComponent textComponent(&engine);
@@ -775,6 +825,8 @@ void tst_qdeclarativetext::style()
QVERIFY(brPre.width() < brPost.width());
QVERIFY(brPre.height() < brPost.height());
+
+ delete textObject;
}
void tst_qdeclarativetext::color()
@@ -789,6 +841,8 @@ void tst_qdeclarativetext::color()
QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
QCOMPARE(textObject->styleColor(), QColor());
+
+ delete textObject;
}
for (int i = 0; i < colorStrings.size(); i++)
@@ -801,6 +855,8 @@ void tst_qdeclarativetext::color()
QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
// default color to black?
QCOMPARE(textObject->color(), QColor("black"));
+
+ delete textObject;
}
for (int i = 0; i < colorStrings.size(); i++)
@@ -814,6 +870,8 @@ void tst_qdeclarativetext::color()
QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
+
+ delete textObject;
}
}
{
@@ -827,6 +885,8 @@ void tst_qdeclarativetext::color()
QDeclarativeText *textObject = qobject_cast<QDeclarativeText*>(textComponent.create());
QCOMPARE(textObject->color(), testColor);
+
+ delete textObject;
}
}
@@ -840,6 +900,8 @@ void tst_qdeclarativetext::smooth()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QDeclarativeText *textObject = qobject_cast<QDeclarativeText*>(textComponent.create());
QCOMPARE(textObject->smooth(), true);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { text: \"" + standard.at(i) + "\" }";
@@ -847,6 +909,8 @@ void tst_qdeclarativetext::smooth()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QDeclarativeText *textObject = qobject_cast<QDeclarativeText*>(textComponent.create());
QCOMPARE(textObject->smooth(), false);
+
+ delete textObject;
}
}
for (int i = 0; i < richText.size(); i++)
@@ -857,6 +921,8 @@ void tst_qdeclarativetext::smooth()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QDeclarativeText *textObject = qobject_cast<QDeclarativeText*>(textComponent.create());
QCOMPARE(textObject->smooth(), true);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { text: \"" + richText.at(i) + "\" }";
@@ -864,6 +930,8 @@ void tst_qdeclarativetext::smooth()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QDeclarativeText *textObject = qobject_cast<QDeclarativeText*>(textComponent.create());
QCOMPARE(textObject->smooth(), false);
+
+ delete textObject;
}
}
}
@@ -878,6 +946,8 @@ void tst_qdeclarativetext::weight()
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Normal);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
@@ -887,6 +957,8 @@ void tst_qdeclarativetext::weight()
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Bold);
+
+ delete textObject;
}
}
@@ -900,6 +972,8 @@ void tst_qdeclarativetext::underline()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().underline(), false);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { font.underline: true; text: \"Hello world!\" }";
@@ -909,6 +983,8 @@ void tst_qdeclarativetext::underline()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().underline(), true);
+
+ delete textObject;
}
}
@@ -922,6 +998,8 @@ void tst_qdeclarativetext::overline()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().overline(), false);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { font.overline: true; text: \"Hello world!\" }";
@@ -931,6 +1009,8 @@ void tst_qdeclarativetext::overline()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().overline(), true);
+
+ delete textObject;
}
}
@@ -944,6 +1024,8 @@ void tst_qdeclarativetext::strikeout()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().strikeOut(), false);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { font.strikeout: true; text: \"Hello world!\" }";
@@ -953,6 +1035,8 @@ void tst_qdeclarativetext::strikeout()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().strikeOut(), true);
+
+ delete textObject;
}
}
@@ -966,6 +1050,8 @@ void tst_qdeclarativetext::capitalization()
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::MixedCase);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
@@ -975,6 +1061,8 @@ void tst_qdeclarativetext::capitalization()
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllUppercase);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
@@ -984,6 +1072,8 @@ void tst_qdeclarativetext::capitalization()
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllLowercase);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
@@ -993,6 +1083,8 @@ void tst_qdeclarativetext::capitalization()
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::SmallCaps);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
@@ -1002,6 +1094,8 @@ void tst_qdeclarativetext::capitalization()
QVERIFY(textObject != 0);
QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::Capitalize);
+
+ delete textObject;
}
}
@@ -1015,6 +1109,8 @@ void tst_qdeclarativetext::letterSpacing()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().letterSpacing(), 0.0);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
@@ -1024,6 +1120,8 @@ void tst_qdeclarativetext::letterSpacing()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().letterSpacing(), -2.);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
@@ -1033,6 +1131,8 @@ void tst_qdeclarativetext::letterSpacing()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().letterSpacing(), 3.);
+
+ delete textObject;
}
}
@@ -1046,6 +1146,8 @@ void tst_qdeclarativetext::wordSpacing()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().wordSpacing(), 0.0);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
@@ -1055,6 +1157,8 @@ void tst_qdeclarativetext::wordSpacing()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().wordSpacing(), -50.);
+
+ delete textObject;
}
{
QString componentStr = "import QtQuick 1.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
@@ -1064,6 +1168,8 @@ void tst_qdeclarativetext::wordSpacing()
QVERIFY(textObject != 0);
QCOMPARE(textObject->font().wordSpacing(), 200.);
+
+ delete textObject;
}
}
@@ -1132,6 +1238,8 @@ void tst_qdeclarativetext::clickLink()
}
QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
+
+ delete textObject;
}
}
@@ -1269,6 +1377,8 @@ void tst_qdeclarativetext::implicitSize()
textObject->resetWidth();
QVERIFY(textObject->width() == textObject->implicitWidth());
QVERIFY(textObject->height() == textObject->implicitHeight());
+
+ delete textObject;
}
void tst_qdeclarativetext::testQtQuick11Attributes()
diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp
index a241241505..821c4ca0f7 100644
--- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp
+++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp
@@ -713,6 +713,8 @@ void tst_qdeclarativetextinput::moveCursorSelection()
QCOMPARE(textinputObject->selectionStart(), selectionStart);
QCOMPARE(textinputObject->selectionEnd(), selectionEnd);
}
+
+ delete textinputObject;
}
void tst_qdeclarativetextinput::moveCursorSelectionSequence_data()
@@ -915,6 +917,8 @@ void tst_qdeclarativetextinput::moveCursorSelectionSequence()
QCOMPARE(textinputObject->selectedText(), testStr.mid(selection2Start, selection2End - selection2Start));
QCOMPARE(textinputObject->selectionStart(), selection2Start);
QCOMPARE(textinputObject->selectionEnd(), selection2End);
+
+ delete textinputObject;
}
void tst_qdeclarativetextinput::mouseSelection_data()
@@ -1712,6 +1716,8 @@ void tst_qdeclarativetextinput::copyAndPaste() {
}
index++;
}
+
+ delete textInput;
#endif
}
@@ -1764,6 +1770,8 @@ void tst_qdeclarativetextinput::passwordCharacter()
textInput->setPasswordCharacter(".");
// QTBUG-12383 content is updated and redrawn
QVERIFY(contentsSize != textInput->contentsSize());
+
+ delete textInput;
}
void tst_qdeclarativetextinput::cursorDelegate()
diff --git a/tests/auto/declarative/qdeclarativev4/data/doubleBoolJump.qml b/tests/auto/declarative/qdeclarativev4/data/doubleBoolJump.qml
new file mode 100644
index 0000000000..e7fb82ca36
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/data/doubleBoolJump.qml
@@ -0,0 +1,18 @@
+import QtQuick 1.0
+
+Rectangle {
+ QtObject {
+ property real output: i1.p1 || i2.p2 == "text" ? 0.7 : 0
+ }
+
+ QtObject {
+ id: i2
+ property string p2
+ }
+
+ QtObject {
+ id: i1
+ property bool p1: false
+ }
+}
+
diff --git a/tests/auto/declarative/qdeclarativev4/data/fetchException.qml b/tests/auto/declarative/qdeclarativev4/data/fetchException.qml
new file mode 100644
index 0000000000..ece8e73199
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/data/fetchException.qml
@@ -0,0 +1,6 @@
+import QtQuick 1.0
+
+Item {
+ property Item data
+ property int a: data.x, 1
+}
diff --git a/tests/auto/declarative/qdeclarativev4/data/logicalOr.2.qml b/tests/auto/declarative/qdeclarativev4/data/logicalOr.2.qml
new file mode 100644
index 0000000000..54fb78b127
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/data/logicalOr.2.qml
@@ -0,0 +1,6 @@
+import Qt.v4 1.0
+
+Result {
+ property string s: "foo" || "bar"
+ result: s == "foo"
+}
diff --git a/tests/auto/declarative/qdeclarativev4/data/logicalOr.qml b/tests/auto/declarative/qdeclarativev4/data/logicalOr.qml
new file mode 100644
index 0000000000..406a7d83eb
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/data/logicalOr.qml
@@ -0,0 +1,6 @@
+import Qt.v4 1.0
+
+Result {
+ property int a: 10
+ result: a == 1 || a == 2
+}
diff --git a/tests/auto/declarative/qdeclarativev4/data/nestedObjectAccess.qml b/tests/auto/declarative/qdeclarativev4/data/nestedObjectAccess.qml
new file mode 100644
index 0000000000..56cd17e41e
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/data/nestedObjectAccess.qml
@@ -0,0 +1,5 @@
+import Qt.v4 1.0
+
+Result {
+ result: nested.result
+}
diff --git a/tests/auto/declarative/qdeclarativev4/data/nullQObject.qml b/tests/auto/declarative/qdeclarativev4/data/nullQObject.qml
new file mode 100644
index 0000000000..283c1a199b
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/data/nullQObject.qml
@@ -0,0 +1,7 @@
+import QtQuick 1.0
+
+Item {
+ property QtObject obj
+ property QtObject test
+ test: obj
+}
diff --git a/tests/auto/declarative/qdeclarativev4/data/qrealToIntRounding.qml b/tests/auto/declarative/qdeclarativev4/data/qrealToIntRounding.qml
new file mode 100644
index 0000000000..f961910f15
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/data/qrealToIntRounding.qml
@@ -0,0 +1,10 @@
+import QtQuick 1.0
+
+QtObject {
+ property int data: 1
+
+ property int test1: 6.6 + data
+ property int test2: 6.2 + data
+ property int test3: 6 + data
+}
+
diff --git a/tests/auto/declarative/qdeclarativev4/data/subscriptionsInConditionalExpressions.qml b/tests/auto/declarative/qdeclarativev4/data/subscriptionsInConditionalExpressions.qml
new file mode 100644
index 0000000000..25483b207d
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/data/subscriptionsInConditionalExpressions.qml
@@ -0,0 +1,11 @@
+import QtQuick 1.0
+
+Item {
+ id: thisTest
+
+ property bool cond: true
+ property real a: 1
+ property real result: cond ? a : a
+
+ PropertyAction { running: true; target: thisTest; property: "a"; value: 2; }
+}
diff --git a/tests/auto/declarative/qdeclarativev4/data/unaryMinus.qml b/tests/auto/declarative/qdeclarativev4/data/unaryMinus.qml
new file mode 100644
index 0000000000..3cfa0492c0
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/data/unaryMinus.qml
@@ -0,0 +1,18 @@
+import QtQuick 1.0
+
+Item {
+ property real test1: -i1.p2
+ property int test2: -i1.p2
+ property real test3: -i1.p1
+ property int test4: -i1.p1
+ property real test5: -i1.p3
+ property int test6: -i1.p3
+
+ QtObject {
+ id: i1
+ property real p1: -3.7
+ property int p2: 18
+ property real p3: -3.3
+ }
+ }
+
diff --git a/tests/auto/declarative/qdeclarativev4/data/unnecessaryReeval.qml b/tests/auto/declarative/qdeclarativev4/data/unnecessaryReeval.qml
new file mode 100644
index 0000000000..48662d7a2d
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/data/unnecessaryReeval.qml
@@ -0,0 +1,7 @@
+import Qt.v4 1.0
+
+Result {
+ property int a: 8
+ property int b: 19
+ result: (a == 8)?b:7
+}
diff --git a/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro b/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro
new file mode 100644
index 0000000000..ee22a04629
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/qdeclarativev4.pro
@@ -0,0 +1,18 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative script network
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qdeclarativev4.cpp \
+ testtypes.cpp
+HEADERS += testtypes.h
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qdeclarativev4/testtypes.cpp b/tests/auto/declarative/qdeclarativev4/testtypes.cpp
new file mode 100644
index 0000000000..f4544b6e21
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/testtypes.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "testtypes.h"
+
+#include <QtDeclarative/qdeclarative.h>
+
+void registerTypes()
+{
+ qmlRegisterType<ResultObject>("Qt.v4", 1,0, "Result");
+ qmlRegisterType<NestedObject>();
+}
diff --git a/tests/auto/declarative/qdeclarativev4/testtypes.h b/tests/auto/declarative/qdeclarativev4/testtypes.h
new file mode 100644
index 0000000000..0933eff8b7
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/testtypes.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef TESTTYPES_H
+#define TESTTYPES_H
+
+#include <QtCore/qobject.h>
+
+class NestedObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int dummy READ dummy);
+ Q_PROPERTY(int result READ result FINAL CONSTANT);
+
+public:
+ int dummy() const { return 7; }
+ int result() const { return 37; }
+};
+
+class ResultObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int result READ result WRITE setResult FINAL)
+ Q_PROPERTY(NestedObject *nested READ nested CONSTANT)
+public:
+ ResultObject() : m_result(0), m_resultCounter(0) {}
+
+ int resultCounter() const { return m_resultCounter; }
+ void resetResultCounter() { m_resultCounter = 0; }
+
+ int result() const { return m_result; }
+ void setResult(int result) { m_result = result; m_resultCounter++; }
+
+ NestedObject *nested() { return &m_nested; }
+
+private:
+ int m_result;
+ int m_resultCounter;
+
+ NestedObject m_nested;
+};
+
+void registerTypes();
+
+#endif // TESTTYPES_H
+
diff --git a/tests/auto/declarative/qdeclarativev4/tst_qdeclarativev4.cpp b/tests/auto/declarative/qdeclarativev4/tst_qdeclarativev4.cpp
new file mode 100644
index 0000000000..0f8c5bcf66
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativev4/tst_qdeclarativev4.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdir.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtCore/qdebug.h>
+
+#include <private/qdeclarativev4compiler_p.h>
+
+#include "testtypes.h"
+
+inline QUrl TEST_FILE(const QString &filename)
+{
+ QFileInfo fileInfo(__FILE__);
+ return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
+}
+
+inline QUrl TEST_FILE(const char *filename)
+{
+ return TEST_FILE(QLatin1String(filename));
+}
+
+class tst_qdeclarativev4 : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qdeclarativev4() {}
+
+private slots:
+ void initTestCase();
+
+ void unnecessaryReeval();
+ void logicalOr();
+ void qtscript();
+ void qtscript_data();
+ void nestedObjectAccess();
+ void subscriptionsInConditionalExpressions();
+
+private:
+ QDeclarativeEngine engine;
+};
+
+void tst_qdeclarativev4::initTestCase()
+{
+ registerTypes();
+}
+
+static int v4ErrorsMsgCount = 0;
+static void v4ErrorsMsgHandler(QtMsgType, const char *message)
+{
+ QByteArray m(message);
+ if (m.contains("QDeclarativeV4"))
+ v4ErrorsMsgCount++;
+}
+
+void tst_qdeclarativev4::qtscript()
+{
+ QFETCH(QString, file);
+ QDeclarativeV4Compiler::enableBindingsTest(true);
+
+ QDeclarativeComponent component(&engine, TEST_FILE(file));
+
+ v4ErrorsMsgCount = 0;
+ QtMsgHandler old = qInstallMsgHandler(v4ErrorsMsgHandler);
+
+ QObject *o = component.create();
+ delete o;
+
+ qInstallMsgHandler(old);
+
+ QCOMPARE(v4ErrorsMsgCount, 0);
+
+ QDeclarativeV4Compiler::enableBindingsTest(false);
+}
+
+void tst_qdeclarativev4::qtscript_data()
+{
+ QTest::addColumn<QString>("file");
+
+ QTest::newRow("qreal -> int rounding") << "qrealToIntRounding.qml";
+ QTest::newRow("exception on fetch") << "fetchException.qml";
+ QTest::newRow("logical or") << "logicalOr.qml";
+ QTest::newRow("double bool jump") << "doubleBoolJump.qml";
+ QTest::newRow("unary minus") << "unaryMinus.qml";
+ QTest::newRow("null qobject") << "nullQObject.qml";
+}
+
+void tst_qdeclarativev4::unnecessaryReeval()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("unnecessaryReeval.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ ResultObject *ro = qobject_cast<ResultObject *>(o);
+ QVERIFY(ro != 0);
+
+ QCOMPARE(ro->resultCounter(), 1);
+ QCOMPARE(ro->result(), 19);
+ ro->resetResultCounter();
+
+ ro->setProperty("b", 6);
+
+ QCOMPARE(ro->resultCounter(), 1);
+ QCOMPARE(ro->result(), 6);
+ ro->resetResultCounter();
+
+ ro->setProperty("a", 14);
+
+ QCOMPARE(ro->resultCounter(), 1);
+ QCOMPARE(ro->result(), 7);
+ ro->resetResultCounter();
+
+ ro->setProperty("b", 14);
+ QCOMPARE(ro->resultCounter(), 0);
+ QCOMPARE(ro->result(), 7);
+
+ delete o;
+}
+
+void tst_qdeclarativev4::logicalOr()
+{
+ {
+ QDeclarativeComponent component(&engine, TEST_FILE("logicalOr.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ ResultObject *ro = qobject_cast<ResultObject *>(o);
+ QVERIFY(ro != 0);
+
+ QCOMPARE(ro->result(), 0);
+ delete o;
+ }
+
+ {
+ QDeclarativeComponent component(&engine, TEST_FILE("logicalOr.2.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ ResultObject *ro = qobject_cast<ResultObject *>(o);
+ QVERIFY(ro != 0);
+
+ QCOMPARE(ro->result(), 1);
+ delete o;
+ }
+}
+
+// This would previously use the metaObject of the root element to result the nested access.
+// That is, the index for accessing "result" would have been RootObject::result, instead of
+// NestedObject::result.
+void tst_qdeclarativev4::nestedObjectAccess()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("nestedObjectAccess.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ ResultObject *ro = qobject_cast<ResultObject *>(o);
+ QVERIFY(ro != 0);
+
+ QCOMPARE(ro->result(), 37);
+
+ delete o;
+}
+
+void tst_qdeclarativev4::subscriptionsInConditionalExpressions()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("subscriptionsInConditionalExpressions.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QObject *ro = qobject_cast<QObject *>(o);
+ QVERIFY(ro != 0);
+
+ QCOMPARE(ro->property("result").toReal(), qreal(2));
+
+ delete o;
+}
+
+QTEST_MAIN(tst_qdeclarativev4)
+
+#include "tst_qdeclarativev4.moc"
diff --git a/tests/auto/declarative/qdeclarativeview/tst_qdeclarativeview.cpp b/tests/auto/declarative/qdeclarativeview/tst_qdeclarativeview.cpp
index 83856597f2..bf2e85139f 100644
--- a/tests/auto/declarative/qdeclarativeview/tst_qdeclarativeview.cpp
+++ b/tests/auto/declarative/qdeclarativeview/tst_qdeclarativeview.cpp
@@ -93,6 +93,8 @@ void tst_QDeclarativeView::scene()
QVERIFY(declarativeItem);
QVERIFY(scene.items().count() > 0);
QCOMPARE(scene.items().at(0), declarativeItem);
+
+ delete view;
}
void tst_QDeclarativeView::resizemodedeclarativeitem()
diff --git a/tests/auto/declarative/qdeclarativexmlhttprequest/tst_qdeclarativexmlhttprequest.cpp b/tests/auto/declarative/qdeclarativexmlhttprequest/tst_qdeclarativexmlhttprequest.cpp
index d0e8c1c143..7f158fce67 100644
--- a/tests/auto/declarative/qdeclarativexmlhttprequest/tst_qdeclarativexmlhttprequest.cpp
+++ b/tests/auto/declarative/qdeclarativexmlhttprequest/tst_qdeclarativexmlhttprequest.cpp
@@ -524,7 +524,7 @@ void tst_qdeclarativexmlhttprequest::send_ignoreData()
QVERIFY(server.isValid());
QVERIFY(server.wait(TEST_FILE("send_ignoreData_PUT.expect"),
TEST_FILE("send_ignoreData.reply"),
- TEST_FILE("testdocument.html")));
+ QUrl()));
QDeclarativeComponent component(&engine, TEST_FILE("send_ignoreData.qml"));
QObject *object = component.beginCreate(engine.rootContext());
diff --git a/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
index 1b9831c1ad..f12bcc32db 100644
--- a/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
+++ b/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
@@ -546,6 +546,8 @@ void tst_QMetaObjectBuilder::property()
QVERIFY(!nullProp.isUser());
QVERIFY(!nullProp.hasStdCppSet());
QVERIFY(!nullProp.isEnumOrFlag());
+ QVERIFY(!nullProp.isConstant());
+ QVERIFY(!nullProp.isFinal());
QCOMPARE(nullProp.index(), 0);
// Add a property and check its attributes.
@@ -563,6 +565,8 @@ void tst_QMetaObjectBuilder::property()
QVERIFY(!prop1.isUser());
QVERIFY(!prop1.hasStdCppSet());
QVERIFY(!prop1.isEnumOrFlag());
+ QVERIFY(!prop1.isConstant());
+ QVERIFY(!prop1.isFinal());
QCOMPARE(prop1.index(), 0);
QCOMPARE(builder.propertyCount(), 1);
@@ -581,6 +585,8 @@ void tst_QMetaObjectBuilder::property()
QVERIFY(!prop2.isUser());
QVERIFY(!prop2.hasStdCppSet());
QVERIFY(!prop2.isEnumOrFlag());
+ QVERIFY(!prop2.isConstant());
+ QVERIFY(!prop2.isFinal());
QCOMPARE(prop2.index(), 1);
QCOMPARE(builder.propertyCount(), 2);
@@ -602,6 +608,8 @@ void tst_QMetaObjectBuilder::property()
prop1.setUser(true);
prop1.setStdCppSet(true);
prop1.setEnumOrFlag(true);
+ prop1.setConstant(true);
+ prop1.setFinal(true);
// Check that prop1 is changed, but prop2 is not.
QCOMPARE(prop1.name(), QByteArray("foo"));
@@ -616,6 +624,8 @@ void tst_QMetaObjectBuilder::property()
QVERIFY(prop1.isUser());
QVERIFY(prop1.hasStdCppSet());
QVERIFY(prop1.isEnumOrFlag());
+ QVERIFY(prop1.isConstant());
+ QVERIFY(prop1.isFinal());
QVERIFY(prop2.isReadable());
QVERIFY(prop2.isWritable());
QCOMPARE(prop2.name(), QByteArray("bar"));
@@ -628,6 +638,8 @@ void tst_QMetaObjectBuilder::property()
QVERIFY(!prop2.isUser());
QVERIFY(!prop2.hasStdCppSet());
QVERIFY(!prop2.isEnumOrFlag());
+ QVERIFY(!prop2.isConstant());
+ QVERIFY(!prop2.isFinal());
// Remove prop1 and check that prop2 becomes index 0.
builder.removeProperty(0);
@@ -643,6 +655,8 @@ void tst_QMetaObjectBuilder::property()
QVERIFY(!prop2.isUser());
QVERIFY(!prop2.hasStdCppSet());
QVERIFY(!prop2.isEnumOrFlag());
+ QVERIFY(!prop2.isConstant());
+ QVERIFY(!prop2.isFinal());
QCOMPARE(prop2.index(), 0);
// Perform index-based lookup again.
@@ -666,6 +680,8 @@ void tst_QMetaObjectBuilder::property()
prop2.setUser(false); \
prop2.setStdCppSet(false); \
prop2.setEnumOrFlag(false); \
+ prop2.setConstant(false); \
+ prop2.setFinal(false); \
} while (0)
#define COUNT_FLAGS() \
((prop2.isReadable() ? 1 : 0) + \
@@ -677,7 +693,9 @@ void tst_QMetaObjectBuilder::property()
(prop2.isEditable() ? 1 : 0) + \
(prop2.isUser() ? 1 : 0) + \
(prop2.hasStdCppSet() ? 1 : 0) + \
- (prop2.isEnumOrFlag() ? 1 : 0))
+ (prop2.isEnumOrFlag() ? 1 : 0) + \
+ (prop2.isConstant() ? 1 : 0) + \
+ (prop2.isFinal() ? 1 : 0))
#define CHECK_FLAG(setFunc,isFunc) \
do { \
CLEAR_FLAGS(); \
@@ -696,6 +714,8 @@ void tst_QMetaObjectBuilder::property()
CHECK_FLAG(setUser, isUser);
CHECK_FLAG(setStdCppSet, hasStdCppSet);
CHECK_FLAG(setEnumOrFlag, isEnumOrFlag);
+ CHECK_FLAG(setConstant, isConstant);
+ CHECK_FLAG(setFinal, isFinal);
// Check that nothing else changed.
QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Properties));
diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.0.png b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.0.png
index a02a00dd78..c4722545dc 100644
--- a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.0.png
+++ b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.0.png
Binary files differ
diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.1.png b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.1.png
index be18b8dc2d..58a293bafa 100644
--- a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.1.png
+++ b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.1.png
Binary files differ
diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.2.png b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.2.png
index e4db4bca2e..65a03a1294 100644
--- a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.2.png
+++ b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.2.png
Binary files differ
diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.3.png b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.3.png
index d464e79d00..d736eca904 100644
--- a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.3.png
+++ b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.3.png
Binary files differ
diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.4.png b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.4.png
index b0b93863e1..d7386b3234 100644
--- a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.4.png
+++ b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.4.png
Binary files differ
diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.5.png b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.5.png
index 4ea4b24e16..3500c07ada 100644
--- a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.5.png
+++ b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.5.png
Binary files differ
diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.6.png b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.6.png
index a115867d2a..7c27234f2e 100644
--- a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.6.png
+++ b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.6.png
Binary files differ
diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.qml b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.qml
index 5f1e8be157..a7c7b339b6 100644
--- a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.qml
+++ b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/data/dynamic.qml
@@ -10,239 +10,239 @@ VisualTest {
}
Frame {
msec: 32
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "0e4c352da978cc130894d1f4ce0a0eb4"
}
Frame {
msec: 48
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "a2e959463144623ba36524f4d4ba1c50"
}
Frame {
msec: 64
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "db8f96a79852b468bf793ac0a88f662b"
}
Frame {
msec: 80
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "d2bf766a1271d31fb2771efa3b60dc92"
}
Frame {
msec: 96
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "c99a42391eb5f41c8a09ae5376438998"
}
Frame {
msec: 112
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "88a11ce1a21c28c8fe83cce52ac81c87"
}
Frame {
msec: 128
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "ebfeb134db6e2ce0226f61c685614644"
}
Frame {
msec: 144
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "39983ecac9b5a7bbf486c5549a806bf3"
}
Frame {
msec: 160
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "8216e55fe99f2cabec9859793dc3b57e"
}
Frame {
msec: 176
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "e0ba0455c1142fbc17e9dae54ddde345"
}
Frame {
msec: 192
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "a06714fb98a25430d3c5e133af5d4c8b"
}
Frame {
msec: 208
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "c87a55800b77a6880ba5859c83a4f9d0"
}
Frame {
msec: 224
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "3c055c7bfca6687f139bf60823f8148f"
}
Frame {
msec: 240
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "756dbaf1c06e1ab82ff5be4290795d66"
}
Frame {
msec: 256
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f9ad4f26264b7b29294998085b8ed36a"
}
Frame {
msec: 272
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 288
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 304
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 320
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 336
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 352
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 368
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 384
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 400
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 416
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 432
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 448
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 464
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 480
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 496
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 512
- hash: "d203c2cb69cb0841827e14bddc206d1f"
+ hash: "f636a172aec19c2fb586021837095b11"
}
Frame {
msec: 528
- hash: "453d5fb9d38f37bb8c23e376de76db06"
+ hash: "f0260c84eae73c072d7a01226cb5bfeb"
}
Frame {
msec: 544
- hash: "c4a103de3b7207b3c6277e8ecf79f7dc"
+ hash: "f65bbbeadff6cd71e397c6183ccd6036"
}
Frame {
msec: 560
- hash: "f58b0eb42d9b6ace87379f205da57550"
+ hash: "9efe8a2c0ffed561658b6d9987d88d80"
}
Frame {
msec: 576
- hash: "3384c5b5939d8297e0834c7cd347d579"
+ hash: "4b93c2cbce50887122533b239678419e"
}
Frame {
msec: 592
- hash: "420b55371c69c6e1a17ef85a600c75d1"
+ hash: "e3f955bf3f71e905073e43507624f11c"
}
Frame {
msec: 608
- hash: "55cc6fb3424ef69d316ef29f6563a025"
+ hash: "1700198250ef7efba094ba37ec9bde23"
}
Frame {
msec: 624
- hash: "045b5ac545e69777b814423f77575990"
+ hash: "f2e150d7c2fe91ec2754e1fb9a88c6ec"
}
Frame {
msec: 640
- hash: "45b05241e8e83180a8d92a37dc859ce0"
+ hash: "ab5c2939088861810771db378cb73362"
}
Frame {
msec: 656
- hash: "97915dfbe4943e1f583ee134bc7a0117"
+ hash: "d2459ace336f1366951e0c7ae5b8ad9e"
}
Frame {
msec: 672
- hash: "9b4ce5ed20dd81698b4dd8e48f799c5c"
+ hash: "7099bf087bb89c3b8846e24126f49b83"
}
Frame {
msec: 688
- hash: "24bdcea108cdbb3898a4d9216e9f9510"
+ hash: "65df13d3e38fb739a646746cb401db8e"
}
Frame {
msec: 704
- hash: "d1427093b1a375e86a69c6f65cb1f8e5"
+ hash: "71479564df994d8db2fc01302e6261c5"
}
Frame {
msec: 720
- hash: "43dd666b15697ae18eb2410017256e4c"
+ hash: "ceb4091d33a136aecc470d5572c0bdae"
}
Frame {
msec: 736
- hash: "8043755f5a8a528353f1e7c310a46a97"
+ hash: "0078ad79eee838839aca53fedda51310"
}
Frame {
msec: 752
- hash: "d6b2ef0cb81395cd7454392aed4571f0"
+ hash: "7d5385582e19594afa40154cc61ef54d"
}
Frame {
msec: 768
- hash: "c249fd272e02cbdde972e85fc6dac695"
+ hash: "372fc45db91d4507a5c3baec9efb9224"
}
Frame {
msec: 784
- hash: "1df5f8fce7b0c102e9902912600054e7"
+ hash: "400f21d4028c09d351609a73510dcde0"
}
Frame {
msec: 800
- hash: "a9d16b180634620e3fe6caacb730885b"
+ hash: "5a3965480d6703fdfcec241deae14db7"
}
Frame {
msec: 816
- hash: "7228ce597720520bc12911fdef70ca86"
+ hash: "4ef441bb3f8ab9da1c3eb0d0f7c33c00"
}
Frame {
msec: 832
- hash: "1faa5c3e72740941234ff4a93388edc9"
+ hash: "7526f27a13471bcee2e8e8fe24384bdb"
}
Frame {
msec: 848
- hash: "997ee1c6d5838153182473a3724df4ad"
+ hash: "69afb4d4af4479ac5b2d5bd39b8a968b"
}
Frame {
msec: 864
- hash: "6ebbc0a0427825ea701f5bb4758f11a2"
+ hash: "c523ae0a884cb56fe1f72744ccfe7d1e"
}
Frame {
msec: 880
- hash: "a2ac19360d631fd6d58f8a5ee85e40b4"
+ hash: "6974ea16d8c13a032283fa9df314fb87"
}
Frame {
msec: 896
- hash: "17a5842b47a220bb8bd74a368cea6c1f"
+ hash: "1635eb85aedbad17fde10da173d612ab"
}
Frame {
msec: 912
- hash: "b37bae9c3384c068a7dd4f1135d3bfaa"
+ hash: "9be18310fd7cf548edbc976e4a470228"
}
Frame {
msec: 928
- hash: "65ffb0b6629364ebc687da7785601abd"
+ hash: "5b8574aa9fa9b93fae64c5b180075090"
}
Frame {
msec: 944
- hash: "27c7a43515fb2d8cddde42263f6ac9df"
+ hash: "285eba0de99a1e1c9c43049b469dad9e"
}
Frame {
msec: 960
- hash: "cc292df8a090c08d135dedf5e2a0af7c"
+ hash: "eb824394813a847c9e7e532b74b17c8a"
}
Frame {
msec: 976
@@ -250,239 +250,239 @@ VisualTest {
}
Frame {
msec: 992
- hash: "59735c8372774b50052d15232d2f6d01"
+ hash: "984a2cf360a1bf2e598d329991107c66"
}
Frame {
msec: 1008
- hash: "9c239c4439009465dd91606ac84a3bf0"
+ hash: "5c70be0eeee3f88981021334668360c8"
}
Frame {
msec: 1024
- hash: "8b9715d6468c8501895545bd84bf7f57"
+ hash: "6f361a3be917e677ed41212382569fea"
}
Frame {
msec: 1040
- hash: "0f7a123bfff1dbe059b6ceb3a3f44180"
+ hash: "ab9035768e6e9f81af8158ea0c42863f"
}
Frame {
msec: 1056
- hash: "c1bc31a379d15ca67d0ffc7139800b3f"
+ hash: "58f3d5fb29352a6788bc9e13a1cb7603"
}
Frame {
msec: 1072
- hash: "ebf470cd7cff4a836da9e721acfd327d"
+ hash: "7f1a415a6fc970244b024305b10ce91e"
}
Frame {
msec: 1088
- hash: "e2b89846459f8ae48117ab4393d493bf"
+ hash: "213d79d582aa8f4f736f5bbbfc7d1926"
}
Frame {
msec: 1104
- hash: "5b980dcc070faf4ab4099cd5f711259c"
+ hash: "391c2c6005de6800064763fbf88b4dda"
}
Frame {
msec: 1120
- hash: "4640ed55c1608d76109407279a1f02db"
+ hash: "641dd4b888edc40c8d7df0ab89ad400d"
}
Frame {
msec: 1136
- hash: "d839b597a3afef61de7b14ffb7ae518e"
+ hash: "7fde8a9ee9cdc10b045431301b7e15bc"
}
Frame {
msec: 1152
- hash: "2810e01355c32d3f7a9352676e6b5eef"
+ hash: "15066ed9165a83cafbd4f15435ed5689"
}
Frame {
msec: 1168
- hash: "f1ac8b222e0068320827564e759e87ba"
+ hash: "19b685a164648283774167a31b1dff43"
}
Frame {
msec: 1184
- hash: "7da89563319dd4045e7f9c40a712d722"
+ hash: "837e73ba982c119c3a940cdcdbfdf440"
}
Frame {
msec: 1200
- hash: "09c55dba364e484eec1a1badb4319003"
+ hash: "c8af92bf004e392f1dc8d1e61746f286"
}
Frame {
msec: 1216
- hash: "defd5c9a8003c58a7bef1930efdd6f29"
+ hash: "a357285710ea7d94fbc0f181b5e226dc"
}
Frame {
msec: 1232
- hash: "0f84e515b41b5c064ece9002e5edff0d"
+ hash: "657e15bee0eed2686fcaffad86343677"
}
Frame {
msec: 1248
- hash: "d1a0405a18fe5b54e79ca0cadf46743b"
+ hash: "994c039fed74a9bae706efe7261cc42d"
}
Frame {
msec: 1264
- hash: "6046feb2fad386ae25ddd0d0e8ecb673"
+ hash: "135ea105bdefd24e49dfb58ad61fbb05"
}
Frame {
msec: 1280
- hash: "b4374b0d9d709b0d7a9f8949616a16bf"
+ hash: "7ac7945f810cf9647b0f72db78076415"
}
Frame {
msec: 1296
- hash: "4d9d7d28f32ce2acd14c8dca0bc11fa0"
+ hash: "c41434915014b4122d5d396fa74127ee"
}
Frame {
msec: 1312
- hash: "384afb63bdf34729132ac57080fa2988"
+ hash: "944f79f98cd54a89b1e833199536e894"
}
Frame {
msec: 1328
- hash: "44ac2a9783c450a8c39b09387f0439e2"
+ hash: "c11291d032471d347e5f51a5865a52c7"
}
Frame {
msec: 1344
- hash: "26e1dfc2b54370f94881c2341b6e0618"
+ hash: "92cca77635d5e1a843b8957ecb092373"
}
Frame {
msec: 1360
- hash: "be47d72ae7c57e255706a8a5afe1fd3f"
+ hash: "dcb56a485e1fe925ecef6224e55ba5b6"
}
Frame {
msec: 1376
- hash: "92cb490b081bccedf0bbdee86dbc50ed"
+ hash: "b8edb8a9b8d4596a8da50fa262929d58"
}
Frame {
msec: 1392
- hash: "1f0a09601474246e94c5ec3763cfa83e"
+ hash: "3eb2b0644f2d6a1b4ebd7516c12330ce"
}
Frame {
msec: 1408
- hash: "73f1a5c57a2c96e18ba894a7adb9a014"
+ hash: "21acefe69cf2c544102fccdccbbbccd5"
}
Frame {
msec: 1424
- hash: "8aa130cf4b2706afc8d582ee4c5f510d"
+ hash: "831593033242f154f89d68f1aa4b6bd3"
}
Frame {
msec: 1440
- hash: "1c0de0f1f4aa5f44bdf774169296487d"
+ hash: "8f23b9a029fcafe05d1369cc39ec703e"
}
Frame {
msec: 1456
- hash: "1e9b701ee63effb760e733ac623d75d7"
+ hash: "6c00a41d0250313a26527f7a39e9f7f3"
}
Frame {
msec: 1472
- hash: "c30620b6d5d41937217fa9d3e0bf367d"
+ hash: "395a67b9e40ac34d17969a10f607e8b6"
}
Frame {
msec: 1488
- hash: "1f96e1da113d4a6cdb7179771ef7967d"
+ hash: "ac1392862993cecbc0f7839b4e2c5ca2"
}
Frame {
msec: 1504
- hash: "aa31458e44ba42a633421e8688a3af7e"
+ hash: "f477222fb643462eeb16813f0b49a93f"
}
Frame {
msec: 1520
- hash: "a7a560c05566d0bbea3f2bf397a0063a"
+ hash: "3064b5af87e3738ee89cbfa408059b89"
}
Frame {
msec: 1536
- hash: "fdd290bc46b86a11afdffb95570d9a67"
+ hash: "ac33fc35a69fa9f8d875bdcd53cc0f75"
}
Frame {
msec: 1552
- hash: "46574d7bfc15bc5b9124eb0e12741724"
+ hash: "cbaaed4b19f9aecdcba8d58546d63d4d"
}
Frame {
msec: 1568
- hash: "aed2015031da6c7e5064fe5fcd1e86e3"
+ hash: "d2f75520a698dd21702b11efab5e3024"
}
Frame {
msec: 1584
- hash: "dea39f30e686771ca516ac32e3dc4cb0"
+ hash: "d7560c4cc6ed89fda71e18d6c6c16ef4"
}
Frame {
msec: 1600
- hash: "4a9839f52a7ee6732c5e18c0d67534be"
+ hash: "147faf9f698d64be191bed1abe09a592"
}
Frame {
msec: 1616
- hash: "df21723df1031542483684ff92aaf40a"
+ hash: "49026a5a6e677b0f0950ed5e5bebb108"
}
Frame {
msec: 1632
- hash: "53683b7b52d0940aac744f0ef03a4527"
+ hash: "8ef3bc4d3f1965eb6e6407eb26de532f"
}
Frame {
msec: 1648
- hash: "e6177b60c5586e79ca82e1bc7af41737"
+ hash: "86fc1e6fd5f230983d9b0b125d2827ef"
}
Frame {
msec: 1664
- hash: "592a60e226aa6967a8a41bc0e4288583"
+ hash: "dde134ab5ae1b7c1f59d58534c16dd03"
}
Frame {
msec: 1680
- hash: "534512915d800d00350803c3fdcccaf3"
+ hash: "53c13b4ff1241d1faa0a94a0730489f7"
}
Frame {
msec: 1696
- hash: "a01ffd7ab177f850f3d8320da19a03ce"
+ hash: "a46d8748063674d2739e44c7f18e941a"
}
Frame {
msec: 1712
- hash: "15bd47f2c5c8cefe7565790b429aa6a4"
+ hash: "b3ec96287e5df1fe058b7672731e6db9"
}
Frame {
msec: 1728
- hash: "b90692eafe68c2b04057af887617667c"
+ hash: "2e671d9f4266ef19f8632c5efe3897a7"
}
Frame {
msec: 1744
- hash: "edb22bd93a83de0cd3a046ed5a513ece"
+ hash: "a0d17185b04ec84d85fe6349ea9f6b5c"
}
Frame {
msec: 1760
- hash: "f08fa88d05f48c42dd1eba538dc464d4"
+ hash: "4ad02b737bc2ec05f935529914b8b694"
}
Frame {
msec: 1776
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "4c0a7a445520155b5ce590d9566ddde7"
}
Frame {
msec: 1792
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "e4108a09f8d944577d96d4697fa32216"
}
Frame {
msec: 1808
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "8ee31240c836bfd6f18a9d2aac5cb084"
}
Frame {
msec: 1824
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "e58b69388d4b30fa96bfb3ecd7ec4fe6"
}
Frame {
msec: 1840
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "e0fb7420fbdde291be7955476fef7c06"
}
Frame {
msec: 1856
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "d19f92d707cc95007cb77555f2bef31b"
}
Frame {
msec: 1872
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "b1af9c47935dda17e533ac9a4078c66c"
}
Frame {
msec: 1888
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "5fd8ee80a9388ca1ff99fe35a3973eff"
}
Frame {
msec: 1904
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "fac7ddc309b6ae477e8da1d87c56a5f1"
}
Frame {
msec: 1920
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "fbcd446ced1a00cfb0b177c7de5d6e60"
}
Frame {
msec: 1936
@@ -490,239 +490,239 @@ VisualTest {
}
Frame {
msec: 1952
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "6d2827458ac8012bb9468ed453e61331"
}
Frame {
msec: 1968
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "2184f41e9b49f9a58e58dc6843a7741a"
}
Frame {
msec: 1984
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "7bfe1cad3611ccb4c55da75546853b25"
}
Frame {
msec: 2000
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "0c1164b69806cd0281b7aa131d8018eb"
}
Frame {
msec: 2016
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "bb531046028c870de76f0a6cfaf23c31"
}
Frame {
msec: 2032
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2048
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2064
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2080
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2096
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2112
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2128
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2144
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2160
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2176
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2192
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2208
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2224
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2240
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2256
- hash: "ec46803523ee0516ed2c89923ff2ded7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2272
- hash: "6b8b68e359f532729bf25a6851563ad7"
+ hash: "56b9c59557c852242fc02921716b4c29"
}
Frame {
msec: 2288
- hash: "1ee3cf0c3c738a909f1b40b4ef49ac50"
+ hash: "940a8ee9cc80ec237c2a0b3c0284de80"
}
Frame {
msec: 2304
- hash: "71889e0f81eeb252dd91a46af5ce24e7"
+ hash: "39860a23099f80ab2a0c979b77c1e41b"
}
Frame {
msec: 2320
- hash: "99390a696ac524d752672df6f2136fa3"
+ hash: "acc2194a277d69177063d06a5c096bc8"
}
Frame {
msec: 2336
- hash: "00919914f1623bb260e0f99b471aa182"
+ hash: "31cde88c34bcf8540ebf27a0f03d3010"
}
Frame {
msec: 2352
- hash: "64bd7ff1518a3e84c4b40511c5c0ff2d"
+ hash: "203ffd5a6efda14f8d8685a3c294f9de"
}
Frame {
msec: 2368
- hash: "b68da721bf79592e49408b098f72e884"
+ hash: "e9dfff40745663c4938b5d0baa28b5f1"
}
Frame {
msec: 2384
- hash: "6a8ca937b7c961c403ab1662d170c1a5"
+ hash: "1d906fdca4cfd51f371d2203770d2cda"
}
Frame {
msec: 2400
- hash: "3f4034da4cd71738d1130c3baa38cf9b"
+ hash: "2fb9d6175f7350b57350e6ab3707918c"
}
Frame {
msec: 2416
- hash: "97a86d3c04d07508604b46732b121edd"
+ hash: "dbe072fc17ee6bc497efb60354ed3758"
}
Frame {
msec: 2432
- hash: "42e9ab3ed744d1a9a7eb5b7a206f29b3"
+ hash: "27dd91387bbfcb381a3d73e4108f6f82"
}
Frame {
msec: 2448
- hash: "ff86192c1b9c0faabb5563260cb1bff2"
+ hash: "8a3e06d17e657aa659c1185ff761c227"
}
Frame {
msec: 2464
- hash: "e1de0e431b971deb546935b6b2fc78e7"
+ hash: "dd476416c45830b4ad8d02b650af7530"
}
Frame {
msec: 2480
- hash: "b7817a7f15d8e727e25719de8cc7d50a"
+ hash: "7fea8ab086376c3f644e24545f3e5382"
}
Frame {
msec: 2496
- hash: "66772971897fc00d01d067e5fc38f848"
+ hash: "e4e8a1838730f3389a5d6630247cc02e"
}
Frame {
msec: 2512
- hash: "175db8c0324af4c206f9673f0a8d0477"
+ hash: "11cd1b8b7b14913036429c7acc688590"
}
Frame {
msec: 2528
- hash: "f3dea687e0ca335b987b6b3c7d736469"
+ hash: "0ff657aa16a82a86f750c0d56a297fc3"
}
Frame {
msec: 2544
- hash: "44d035dd8e302b75c5a7f98a2005fe75"
+ hash: "e6cf7e1d446652270865857a801f4bc3"
}
Frame {
msec: 2560
- hash: "140cf53cb6873b14e6263537f84b0aa0"
+ hash: "db9021619dd192122857dffd2b25b18d"
}
Frame {
msec: 2576
- hash: "6c9090d4488289e69562747271459d7d"
+ hash: "77772d2e14b85df151085500e45020c2"
}
Frame {
msec: 2592
- hash: "49e92db256f5be8c4e35566eea8fca70"
+ hash: "a49744a9c4c6c1f2392184d13907f404"
}
Frame {
msec: 2608
- hash: "80f41d2eb743ee13fcc486651e310fe2"
+ hash: "2701f2dd7196402e228475ce739fbe5b"
}
Frame {
msec: 2624
- hash: "f581fdcaf30c0efd4518e538e88c2ebf"
+ hash: "71030d54a9a9cf234731d8bfd4985442"
}
Frame {
msec: 2640
- hash: "c028db6753cf60bf587e6c46080a31ea"
+ hash: "c5b6c4bc0b68aff9d589bbc4781c6f4d"
}
Frame {
msec: 2656
- hash: "231b69aa9bdadbaf47cbfbc44a322a51"
+ hash: "3ef8d76256628e782b56b3c6e7d3f7d8"
}
Frame {
msec: 2672
- hash: "f0bcc02aaab3fad2ff53fc2d7541d4aa"
+ hash: "85b0582aa0aaeb72201f2b3284f8fe02"
}
Frame {
msec: 2688
- hash: "80e34154585ba3480e37eaac6bfa396c"
+ hash: "26828739f7a1ed5b7c7823c1cac73b12"
}
Frame {
msec: 2704
- hash: "e1ebf3ba98b2df53ac9f72744034ba6d"
+ hash: "73b85e718117b919b6e3bed087330475"
}
Frame {
msec: 2720
- hash: "b8f749a58888f90ed5cabe7aa2eee1ee"
+ hash: "726deda1001db3f57939a1842c90331d"
}
Frame {
msec: 2736
- hash: "3a78458aa124a331f5b1616be5eea914"
+ hash: "980266e772178b550abb6e24e2a6d659"
}
Frame {
msec: 2752
- hash: "c442c02859bc35a8e5493200e68b1730"
+ hash: "b15bd1cef519d7112edf0f8e97c507ce"
}
Frame {
msec: 2768
- hash: "0cc4d24a1e1fa75a339a5b3dd07f18f3"
+ hash: "1df1a43aed86aedd425846a87c7b5df3"
}
Frame {
msec: 2784
- hash: "0d124bc578058db99e32d58f4b412758"
+ hash: "26cbc843753b51f37a5a84f3b9c7cf56"
}
Frame {
msec: 2800
- hash: "fc174a039606c5457532c9ac27c6faec"
+ hash: "8c3ad31d69f44dc1dbb3bec0476a0cac"
}
Frame {
msec: 2816
- hash: "db5d25d7c01605ec81cdab3e239a1f0f"
+ hash: "9c4243132637e722abee587ae76218c3"
}
Frame {
msec: 2832
- hash: "7dcffdbf9ac992aac0751bed5c38a0eb"
+ hash: "fd99e719c7a6da7c3c309c6a56aeb127"
}
Frame {
msec: 2848
- hash: "b59dc4f39b3e032d5cd34ffca098889f"
+ hash: "4855b585340b25e9cf98c55a9e661a32"
}
Frame {
msec: 2864
- hash: "925d232189a3eee4bae08a8fe86a488b"
+ hash: "d400eb6473515193409d5fe928c17b3b"
}
Frame {
msec: 2880
- hash: "4ab3a889e27de8f45670c240f6d452a6"
+ hash: "d2cabdc2e1b5219242e3768c256cf20a"
}
Frame {
msec: 2896
@@ -730,239 +730,239 @@ VisualTest {
}
Frame {
msec: 2912
- hash: "9b8629b588dcb840fcd32f73f66016ee"
+ hash: "f22d7ebcfecf8ed0aedc10eaf3975a06"
}
Frame {
msec: 2928
- hash: "dca8e45e930314a860f36343f4577738"
+ hash: "71fa22835d65dfd5ded2e3f925a2006f"
}
Frame {
msec: 2944
- hash: "b68f3b38e154b65225211c6a1ca8ddb8"
+ hash: "1fa97a0e9cd3601e830810a397678470"
}
Frame {
msec: 2960
- hash: "d8168aea7962cad60132da9baf66f95c"
+ hash: "3fdb2cf62768af6e89b5fcca4a0fbdcc"
}
Frame {
msec: 2976
- hash: "6f83cd7be71666e08172a2c59e715f2e"
+ hash: "24fa2ed5c9c42eb1013c790c394dccb2"
}
Frame {
msec: 2992
- hash: "f98c68954ed98f340e86c159fcf4f013"
+ hash: "c0b8c6b8d925fac2d5349bab8094ea3a"
}
Frame {
msec: 3008
- hash: "e4692a0e6d82864e9027bcf893e0cf90"
+ hash: "246539b2c38f54cc46ccced49a0964b1"
}
Frame {
msec: 3024
- hash: "ed02ff4d37ad03c0d0d53cf8163ed1c5"
+ hash: "dc27d0928673409db160c25c523b5543"
}
Frame {
msec: 3040
- hash: "fb116353a2ceabae2d93c9aac48727d8"
+ hash: "f6c5694157409606a21455e4ce875e74"
}
Frame {
msec: 3056
- hash: "7b8c99b86838c46db4e756cc039ba045"
+ hash: "3060d75d6ee0d6022d7692aeee90aff2"
}
Frame {
msec: 3072
- hash: "c8d8e194bc957402fe2236b1a472faa6"
+ hash: "0a9bc75adf171200f44892d265f10206"
}
Frame {
msec: 3088
- hash: "f0f3d8c8ac3604cd11b7492fe5ee023e"
+ hash: "30681d928e035188fa25983076b00a24"
}
Frame {
msec: 3104
- hash: "b41cf314e4684423b4708ccd55904d60"
+ hash: "fd007bee6889d3dc8203bf59ff564ba2"
}
Frame {
msec: 3120
- hash: "4f578969386627b6e620e83bad5a6a6c"
+ hash: "559b7f479ae2a2a70288ddde6a18b33e"
}
Frame {
msec: 3136
- hash: "bd9fcfaa4e79f969548af12d072c1ec2"
+ hash: "75d7ce28879ec23f1af3eec3afd94f60"
}
Frame {
msec: 3152
- hash: "a418dc92f8b04fddf95f38bd24825ee6"
+ hash: "f0006440cd257667547b243f69dfdc65"
}
Frame {
msec: 3168
- hash: "4684b3e318a08f0f2331a13143592d18"
+ hash: "9c332ab37fc90bf81cea9eee353352d5"
}
Frame {
msec: 3184
- hash: "1e135a4fd2e7336d8a59ca3497374a3d"
+ hash: "c1313a45a5d85d17b0d82c1b7cb8d4b9"
}
Frame {
msec: 3200
- hash: "d1be76e2c56422b469a9d09e22f62df5"
+ hash: "de50c0522865995d1931f2149494c43c"
}
Frame {
msec: 3216
- hash: "8827523a7f8fa89a56d932102dff7b52"
+ hash: "2a946bfe7a75a519064dc40b27b8b843"
}
Frame {
msec: 3232
- hash: "e12e6b907af5e6feffed0b9e68c71895"
+ hash: "3adb068d2540371cbcd7603a87515716"
}
Frame {
msec: 3248
- hash: "7bc3605f5f241170732aba19ca649896"
+ hash: "11f396595eb3940371a2f8cf497d8184"
}
Frame {
msec: 3264
- hash: "d7da9274f30cacd419f0b0b7c8c8a728"
+ hash: "0c08d7cb54e14120e9f063ed97224e3d"
}
Frame {
msec: 3280
- hash: "154775464235d2a2fb338c27f1490f27"
+ hash: "df9164673edc8c4922696f8999c8d53c"
}
Frame {
msec: 3296
- hash: "1657f65e8759eec3c026262bb271dd1c"
+ hash: "b0fa87c11b235dab2a4361d1c1162866"
}
Frame {
msec: 3312
- hash: "29b4c68846aab3c1dcf4e58861915c33"
+ hash: "746807f46bb1a14890bf7b23ae538a6e"
}
Frame {
msec: 3328
- hash: "fe22b3b991a80b34d6fe12515bfa2fd0"
+ hash: "e856cf08ebebba22e04bcaad1ba75309"
}
Frame {
msec: 3344
- hash: "961343bb9dcc1fbe81b4c20392c28cb9"
+ hash: "edf1ae03a0c60f157f2eb4312226ce3e"
}
Frame {
msec: 3360
- hash: "a2adb3179465e34b517bf906491a1b60"
+ hash: "0c9356e38d0a2b5cbf73b5dd9c76e80d"
}
Frame {
msec: 3376
- hash: "067fb8a2f5043dd4616fb1539e3e9c4a"
+ hash: "eb0fca481da55aeebb0c2ed08e7b2dd0"
}
Frame {
msec: 3392
- hash: "009329915e9027d77218fd83334960ed"
+ hash: "b0c91c68b7c69f3c1124326d8776881c"
}
Frame {
msec: 3408
- hash: "81b05d8aef8152830c6f199d6dd94fd5"
+ hash: "09c76b1c7758e086c1a99198643d29cc"
}
Frame {
msec: 3424
- hash: "b23fa537f88a97490e48fb3a8cd4b507"
+ hash: "294429db9fae8d1a08f34b774ad82124"
}
Frame {
msec: 3440
- hash: "182464f620768efe0253c97cda75d839"
+ hash: "460fbaffccf1cf78b19ab58ed374cec2"
}
Frame {
msec: 3456
- hash: "f1ddbec396cead5d4acf9b65822becb6"
+ hash: "91517b862c3a5c89d8bbc0575b506d3c"
}
Frame {
msec: 3472
- hash: "a73085722d33638517b3f60a16ce9fcd"
+ hash: "4a22f6736a64093790e49a65f3a74923"
}
Frame {
msec: 3488
- hash: "ecce53b0c525834341ee4b3c546e670c"
+ hash: "8ec21c12a499919a46d44b927837db46"
}
Frame {
msec: 3504
- hash: "86f1da737164290a90c1aef9355e2375"
+ hash: "51551a03b495bbd979d2dfbabb33f852"
}
Frame {
msec: 3520
- hash: "722ec874122ad8dcc73820a3a2fb7dca"
+ hash: "700ad73013037cbf10694e712212a799"
}
Frame {
msec: 3536
- hash: "35eb086b11482b752e2c02f1dc4d9099"
+ hash: "bd305b17ba9542ae01a2934bb5c2784f"
}
Frame {
msec: 3552
- hash: "83cf9c0b5d0afd5d3cee4c446274f5c4"
+ hash: "91cf99daf3ff442ea43274ba9ce4bceb"
}
Frame {
msec: 3568
- hash: "e1bbef11fe02adb0756113e1106fe7f1"
+ hash: "7d33d2f8684f1947e01e6144e84ba1f6"
}
Frame {
msec: 3584
- hash: "774c8bb4585954274852d6bb07e64916"
+ hash: "e23e50737d3b70132a0abc91f6900952"
}
Frame {
msec: 3600
- hash: "b0264bcddf313d4e819a608143a86ac9"
+ hash: "4a31ea946579b1a09364d0197aed9943"
}
Frame {
msec: 3616
- hash: "5e3859fd56e5022cbc7831e22447f05d"
+ hash: "d3abb24ef7dea1b32180a34acd1901a0"
}
Frame {
msec: 3632
- hash: "8c2a8b7321d2598b08d483914d4f319c"
+ hash: "19b413d918888038c26109528c8b96da"
}
Frame {
msec: 3648
- hash: "f13913dbc015836e35d5a2ebc94bbeef"
+ hash: "d1a19db5ce841914b6599dd257dc4a6d"
}
Frame {
msec: 3664
- hash: "1309af996f2d7a686f1d9177bc5c9be6"
+ hash: "24e29dd07133ac8c8d51dd6aac07e5ce"
}
Frame {
msec: 3680
- hash: "460b3500b41624486fe8dcfde087d2b5"
+ hash: "db7ae9587b8fcd766e23ffdd8e92cac2"
}
Frame {
msec: 3696
- hash: "de0837d19497021528dc782db4da084a"
+ hash: "0314577dd3497f2cc70e503058ff0c1d"
}
Frame {
msec: 3712
- hash: "18afb8f8e9aa6d4a5db376e26cd9a56d"
+ hash: "ae0dbd41a6e1b7bc87184a059a2b2e61"
}
Frame {
msec: 3728
- hash: "4fc1a8173824c2725160798b7d70aec2"
+ hash: "43c446b3cb9854e35dd21e7da7aa986f"
}
Frame {
msec: 3744
- hash: "87a593f74c946d6af6e31c5a25898766"
+ hash: "675e049ffabad0179f9e94332e457b97"
}
Frame {
msec: 3760
- hash: "57e68ec2aa5a21b11d21f388399713e5"
+ hash: "ef272f944e95e2c08a856066d2d082c2"
}
Frame {
msec: 3776
- hash: "4cb9ee1d12b99fb98bedcbcc048867e4"
+ hash: "2d34ec460d21fdeb5daddf9245f8c5cf"
}
Frame {
msec: 3792
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "e94a08e34a7cbd406937c1ffddcbb185"
}
Frame {
msec: 3808
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "22523265a7cbbcfc2182ac1521c8dca8"
}
Frame {
msec: 3824
- hash: "a0c46402b4700cc2099bdf42c47faf9b"
+ hash: "e5f95a7f0d9cd2a4ca54a9e5a6783c8a"
}
Frame {
msec: 3840
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "da7c216b89e1b8f261d2979be8cc61a7"
}
Frame {
msec: 3856
@@ -970,239 +970,239 @@ VisualTest {
}
Frame {
msec: 3872
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "08b3de4eea6ecbe85ab7b104e0571815"
}
Frame {
msec: 3888
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "66b5d695c3fdf6c5fa08241c39c1bff9"
}
Frame {
msec: 3904
- hash: "b692386f34972d80aded2347e64ad2b6"
+ hash: "25f2403ff19575e94010980e02015d64"
}
Frame {
msec: 3920
- hash: "dc65b0a791002efffec05884aa948842"
+ hash: "5d8d901818a21965cb54b477592b65a5"
}
Frame {
msec: 3936
- hash: "069bab78e29d322894647f81d315184a"
+ hash: "4cbe77985c9dea4c37f08135ac0e8882"
}
Frame {
msec: 3952
- hash: "39c8d804b3caf53845baba4ce98e007d"
+ hash: "8e4dcb566347ecf31c2c7c9262f3c71d"
}
Frame {
msec: 3968
- hash: "3b477dfd05f07bdf0ba562d6068cafdb"
+ hash: "71b810ad39750acd84d06526e6ec0767"
}
Frame {
msec: 3984
- hash: "eb84ee75bdbf25dcc32587007f5dc9bd"
+ hash: "79eee90dbf4ba9992dca0e9e4ef02350"
}
Frame {
msec: 4000
- hash: "441d34bff2755e3c30bed80e2bdde69c"
+ hash: "cfc32ce2407a6d8a84fe99393c5d5d9e"
}
Frame {
msec: 4016
- hash: "4cb9ee1d12b99fb98bedcbcc048867e4"
+ hash: "af880ae1f0eb620a416cea66216f2509"
}
Frame {
msec: 4032
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "e0aab4701e9039386c6f3f3ae7c86265"
}
Frame {
msec: 4048
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "957cd332444c819fecc4c58149cc6782"
}
Frame {
msec: 4064
- hash: "a0c46402b4700cc2099bdf42c47faf9b"
+ hash: "c7395c37477b4c39bb22d5cb6f0649fe"
}
Frame {
msec: 4080
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "992f62d1cc929e3d92008bf2581c4b4b"
}
Frame {
msec: 4096
- hash: "c92cba3c2825db4293153588c4b7b229"
+ hash: "d8f079d91944796401b86296788a2250"
}
Frame {
msec: 4112
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "7df19eeae14a578760613075e611c9a6"
}
Frame {
msec: 4128
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "998f8f07b857d0c4b740be8a323c6e9a"
}
Frame {
msec: 4144
- hash: "b692386f34972d80aded2347e64ad2b6"
+ hash: "9419aae1cfd8592031dbe26223700ed0"
}
Frame {
msec: 4160
- hash: "dc65b0a791002efffec05884aa948842"
+ hash: "fc9d9216599cf59e16f4344cf43c27f5"
}
Frame {
msec: 4176
- hash: "069bab78e29d322894647f81d315184a"
+ hash: "e43d779e9edbde4f6e47bf13653464f8"
}
Frame {
msec: 4192
- hash: "39c8d804b3caf53845baba4ce98e007d"
+ hash: "d482896bddc89c4739674877be15972c"
}
Frame {
msec: 4208
- hash: "3b477dfd05f07bdf0ba562d6068cafdb"
+ hash: "9cf23658545ac1d744c6c549a86b561d"
}
Frame {
msec: 4224
- hash: "eb84ee75bdbf25dcc32587007f5dc9bd"
+ hash: "79eee90dbf4ba9992dca0e9e4ef02350"
}
Frame {
msec: 4240
- hash: "441d34bff2755e3c30bed80e2bdde69c"
+ hash: "cfc32ce2407a6d8a84fe99393c5d5d9e"
}
Frame {
msec: 4256
- hash: "57e68ec2aa5a21b11d21f388399713e5"
+ hash: "377a5cd9be5f70975fe74d4de1bf2e70"
}
Frame {
msec: 4272
- hash: "4cb9ee1d12b99fb98bedcbcc048867e4"
+ hash: "af880ae1f0eb620a416cea66216f2509"
}
Frame {
msec: 4288
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "afb15151f2bd529817c4a1053dab6e9e"
}
Frame {
msec: 4304
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "113af4013655488c3389abfcfdd25c8a"
}
Frame {
msec: 4320
- hash: "a0c46402b4700cc2099bdf42c47faf9b"
+ hash: "fe92ba0e4552bbfd26858c30ff2dbe78"
}
Frame {
msec: 4336
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "374ca32f24189773ba181d375107a1bd"
}
Frame {
msec: 4352
- hash: "c92cba3c2825db4293153588c4b7b229"
+ hash: "8de169d6ec0a3ecb13b39f93b2ccabbd"
}
Frame {
msec: 4368
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "53c65f25dc0b915d500ef091a45c1b2b"
}
Frame {
msec: 4384
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "846a5983865f87f5058eca31f056d021"
}
Frame {
msec: 4400
- hash: "b692386f34972d80aded2347e64ad2b6"
+ hash: "7243fe48f5cbf172b67ea8658d489a31"
}
Frame {
msec: 4416
- hash: "dc65b0a791002efffec05884aa948842"
+ hash: "4fbcfc907361ccbe5ec5d945cb49065e"
}
Frame {
msec: 4432
- hash: "069bab78e29d322894647f81d315184a"
+ hash: "e450930da4d7838a2539a73bb3e8b9e3"
}
Frame {
msec: 4448
- hash: "39c8d804b3caf53845baba4ce98e007d"
+ hash: "d482896bddc89c4739674877be15972c"
}
Frame {
msec: 4464
- hash: "3b477dfd05f07bdf0ba562d6068cafdb"
+ hash: "9cf23658545ac1d744c6c549a86b561d"
}
Frame {
msec: 4480
- hash: "eb84ee75bdbf25dcc32587007f5dc9bd"
+ hash: "79eee90dbf4ba9992dca0e9e4ef02350"
}
Frame {
msec: 4496
- hash: "441d34bff2755e3c30bed80e2bdde69c"
+ hash: "cfc32ce2407a6d8a84fe99393c5d5d9e"
}
Frame {
msec: 4512
- hash: "57e68ec2aa5a21b11d21f388399713e5"
+ hash: "377a5cd9be5f70975fe74d4de1bf2e70"
}
Frame {
msec: 4528
- hash: "4cb9ee1d12b99fb98bedcbcc048867e4"
+ hash: "af880ae1f0eb620a416cea66216f2509"
}
Frame {
msec: 4544
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "bb73c7d58cfca18e8dc8c256ceaa6dba"
}
Frame {
msec: 4560
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "ab2f94beae7447d2c25808e0ff2d3397"
}
Frame {
msec: 4576
- hash: "a0c46402b4700cc2099bdf42c47faf9b"
+ hash: "0e731803c864f753809daa22ff9f76c7"
}
Frame {
msec: 4592
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "48874688b1eb19d67bdf91653f4ce74e"
}
Frame {
msec: 4608
- hash: "c92cba3c2825db4293153588c4b7b229"
+ hash: "3aac3fc7526ad990fcd4a7a4eb162a10"
}
Frame {
msec: 4624
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "72b92331f80f37480ac208b4cce4fdb2"
}
Frame {
msec: 4640
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "4cc992953df7636b9b1b063f87ae36fa"
}
Frame {
msec: 4656
- hash: "b692386f34972d80aded2347e64ad2b6"
+ hash: "012078bb87950fdb960e2679a47c4bf6"
}
Frame {
msec: 4672
- hash: "dc65b0a791002efffec05884aa948842"
+ hash: "4fbcfc907361ccbe5ec5d945cb49065e"
}
Frame {
msec: 4688
- hash: "069bab78e29d322894647f81d315184a"
+ hash: "e450930da4d7838a2539a73bb3e8b9e3"
}
Frame {
msec: 4704
- hash: "39c8d804b3caf53845baba4ce98e007d"
+ hash: "d482896bddc89c4739674877be15972c"
}
Frame {
msec: 4720
- hash: "3b477dfd05f07bdf0ba562d6068cafdb"
+ hash: "9cf23658545ac1d744c6c549a86b561d"
}
Frame {
msec: 4736
- hash: "eb84ee75bdbf25dcc32587007f5dc9bd"
+ hash: "79eee90dbf4ba9992dca0e9e4ef02350"
}
Frame {
msec: 4752
- hash: "441d34bff2755e3c30bed80e2bdde69c"
+ hash: "cfc32ce2407a6d8a84fe99393c5d5d9e"
}
Frame {
msec: 4768
- hash: "4cb9ee1d12b99fb98bedcbcc048867e4"
+ hash: "af880ae1f0eb620a416cea66216f2509"
}
Frame {
msec: 4784
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "f1cd43dfe4d2846c7f3a8a6af19174d0"
}
Frame {
msec: 4800
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "0eedf77ea428a6ff55507c241588b0a5"
}
Frame {
msec: 4816
@@ -1210,239 +1210,239 @@ VisualTest {
}
Frame {
msec: 4832
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "18625884760a6ecb9b37c609afea0a29"
}
Frame {
msec: 4848
- hash: "c92cba3c2825db4293153588c4b7b229"
+ hash: "2504012907c89b8578b804811bc27d8e"
}
Frame {
msec: 4864
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "559e27ede74f57b25ce889df1c211f4f"
}
Frame {
msec: 4880
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "7f788af35c7190d04bdc06cbf921c83d"
}
Frame {
msec: 4896
- hash: "b692386f34972d80aded2347e64ad2b6"
+ hash: "012078bb87950fdb960e2679a47c4bf6"
}
Frame {
msec: 4912
- hash: "dc65b0a791002efffec05884aa948842"
+ hash: "4fbcfc907361ccbe5ec5d945cb49065e"
}
Frame {
msec: 4928
- hash: "069bab78e29d322894647f81d315184a"
+ hash: "e450930da4d7838a2539a73bb3e8b9e3"
}
Frame {
msec: 4944
- hash: "39c8d804b3caf53845baba4ce98e007d"
+ hash: "d482896bddc89c4739674877be15972c"
}
Frame {
msec: 4960
- hash: "3b477dfd05f07bdf0ba562d6068cafdb"
+ hash: "9cf23658545ac1d744c6c549a86b561d"
}
Frame {
msec: 4976
- hash: "eb84ee75bdbf25dcc32587007f5dc9bd"
+ hash: "79eee90dbf4ba9992dca0e9e4ef02350"
}
Frame {
msec: 4992
- hash: "441d34bff2755e3c30bed80e2bdde69c"
+ hash: "cfc32ce2407a6d8a84fe99393c5d5d9e"
}
Frame {
msec: 5008
- hash: "57e68ec2aa5a21b11d21f388399713e5"
+ hash: "377a5cd9be5f70975fe74d4de1bf2e70"
}
Frame {
msec: 5024
- hash: "4cb9ee1d12b99fb98bedcbcc048867e4"
+ hash: "af880ae1f0eb620a416cea66216f2509"
}
Frame {
msec: 5040
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "a0bdd440290cc09c86d65b2f74079b97"
}
Frame {
msec: 5056
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "b0f7c2289283b78016394b900fa3dfcb"
}
Frame {
msec: 5072
- hash: "a0c46402b4700cc2099bdf42c47faf9b"
+ hash: "e39fe4762a948bbc412e9b7160f2e439"
}
Frame {
msec: 5088
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "30ae9eaa6b96a00a83faf349d450be3b"
}
Frame {
msec: 5104
- hash: "c92cba3c2825db4293153588c4b7b229"
+ hash: "21178cc44036162ca6f03dd876b38d14"
}
Frame {
msec: 5120
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "cea64ba789fda0f8bdd4ef64321e1c23"
}
Frame {
msec: 5136
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "7f788af35c7190d04bdc06cbf921c83d"
}
Frame {
msec: 5152
- hash: "b692386f34972d80aded2347e64ad2b6"
+ hash: "012078bb87950fdb960e2679a47c4bf6"
}
Frame {
msec: 5168
- hash: "dc65b0a791002efffec05884aa948842"
+ hash: "4fbcfc907361ccbe5ec5d945cb49065e"
}
Frame {
msec: 5184
- hash: "069bab78e29d322894647f81d315184a"
+ hash: "e450930da4d7838a2539a73bb3e8b9e3"
}
Frame {
msec: 5200
- hash: "39c8d804b3caf53845baba4ce98e007d"
+ hash: "d482896bddc89c4739674877be15972c"
}
Frame {
msec: 5216
- hash: "3b477dfd05f07bdf0ba562d6068cafdb"
+ hash: "9cf23658545ac1d744c6c549a86b561d"
}
Frame {
msec: 5232
- hash: "eb84ee75bdbf25dcc32587007f5dc9bd"
+ hash: "79eee90dbf4ba9992dca0e9e4ef02350"
}
Frame {
msec: 5248
- hash: "441d34bff2755e3c30bed80e2bdde69c"
+ hash: "cfc32ce2407a6d8a84fe99393c5d5d9e"
}
Frame {
msec: 5264
- hash: "57e68ec2aa5a21b11d21f388399713e5"
+ hash: "377a5cd9be5f70975fe74d4de1bf2e70"
}
Frame {
msec: 5280
- hash: "4cb9ee1d12b99fb98bedcbcc048867e4"
+ hash: "af880ae1f0eb620a416cea66216f2509"
}
Frame {
msec: 5296
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "29f1b978ff683024c0be776cc13ad9d4"
}
Frame {
msec: 5312
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "c9660cbe54cb6ada5b6598990d6fb434"
}
Frame {
msec: 5328
- hash: "a0c46402b4700cc2099bdf42c47faf9b"
+ hash: "592fe8fec20701536706623fda7c86d6"
}
Frame {
msec: 5344
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "1ef2067c92e3621fb0e5080f379b551f"
}
Frame {
msec: 5360
- hash: "c92cba3c2825db4293153588c4b7b229"
+ hash: "16e8dbd8061e0a2433300b6ef0396f8a"
}
Frame {
msec: 5376
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "3ed37ab35b06f483b984014266bf59ea"
}
Frame {
msec: 5392
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "7f788af35c7190d04bdc06cbf921c83d"
}
Frame {
msec: 5408
- hash: "b692386f34972d80aded2347e64ad2b6"
+ hash: "012078bb87950fdb960e2679a47c4bf6"
}
Frame {
msec: 5424
- hash: "dc65b0a791002efffec05884aa948842"
+ hash: "4fbcfc907361ccbe5ec5d945cb49065e"
}
Frame {
msec: 5440
- hash: "069bab78e29d322894647f81d315184a"
+ hash: "e450930da4d7838a2539a73bb3e8b9e3"
}
Frame {
msec: 5456
- hash: "39c8d804b3caf53845baba4ce98e007d"
+ hash: "d482896bddc89c4739674877be15972c"
}
Frame {
msec: 5472
- hash: "3b477dfd05f07bdf0ba562d6068cafdb"
+ hash: "9cf23658545ac1d744c6c549a86b561d"
}
Frame {
msec: 5488
- hash: "eb84ee75bdbf25dcc32587007f5dc9bd"
+ hash: "79eee90dbf4ba9992dca0e9e4ef02350"
}
Frame {
msec: 5504
- hash: "441d34bff2755e3c30bed80e2bdde69c"
+ hash: "cfc32ce2407a6d8a84fe99393c5d5d9e"
}
Frame {
msec: 5520
- hash: "4cb9ee1d12b99fb98bedcbcc048867e4"
+ hash: "af880ae1f0eb620a416cea66216f2509"
}
Frame {
msec: 5536
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "231774644c0b105596b37cec696ca287"
}
Frame {
msec: 5552
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "4230f38c6e85a37e809840f46c060e39"
}
Frame {
msec: 5568
- hash: "a0c46402b4700cc2099bdf42c47faf9b"
+ hash: "385e9542036e82f8ca3c390493777c1c"
}
Frame {
msec: 5584
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "814ab09f3c07c6288f774618282d76e2"
}
Frame {
msec: 5600
- hash: "c92cba3c2825db4293153588c4b7b229"
+ hash: "b5d69dff8c1b995749e39e578ea67de4"
}
Frame {
msec: 5616
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "3ed37ab35b06f483b984014266bf59ea"
}
Frame {
msec: 5632
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "7f788af35c7190d04bdc06cbf921c83d"
}
Frame {
msec: 5648
- hash: "b692386f34972d80aded2347e64ad2b6"
+ hash: "012078bb87950fdb960e2679a47c4bf6"
}
Frame {
msec: 5664
- hash: "dc65b0a791002efffec05884aa948842"
+ hash: "4fbcfc907361ccbe5ec5d945cb49065e"
}
Frame {
msec: 5680
- hash: "069bab78e29d322894647f81d315184a"
+ hash: "e450930da4d7838a2539a73bb3e8b9e3"
}
Frame {
msec: 5696
- hash: "39c8d804b3caf53845baba4ce98e007d"
+ hash: "d482896bddc89c4739674877be15972c"
}
Frame {
msec: 5712
- hash: "3b477dfd05f07bdf0ba562d6068cafdb"
+ hash: "9cf23658545ac1d744c6c549a86b561d"
}
Frame {
msec: 5728
- hash: "eb84ee75bdbf25dcc32587007f5dc9bd"
+ hash: "79eee90dbf4ba9992dca0e9e4ef02350"
}
Frame {
msec: 5744
- hash: "441d34bff2755e3c30bed80e2bdde69c"
+ hash: "cfc32ce2407a6d8a84fe99393c5d5d9e"
}
Frame {
msec: 5760
- hash: "57e68ec2aa5a21b11d21f388399713e5"
+ hash: "377a5cd9be5f70975fe74d4de1bf2e70"
}
Frame {
msec: 5776
@@ -1450,154 +1450,154 @@ VisualTest {
}
Frame {
msec: 5792
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "b364b0db3d8ded941705179153a0a0d9"
}
Frame {
msec: 5808
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "398a0dc7a138f36dea27dfad528324e4"
}
Frame {
msec: 5824
- hash: "a0c46402b4700cc2099bdf42c47faf9b"
+ hash: "f2bd86fe4532cf41fba7f70d7ee1b36f"
}
Frame {
msec: 5840
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "b905dbc82ff13dee50249268b80067b2"
}
Frame {
msec: 5856
- hash: "c92cba3c2825db4293153588c4b7b229"
+ hash: "02aa690ffbecf879f7f98fecace8e0b6"
}
Frame {
msec: 5872
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "3ed37ab35b06f483b984014266bf59ea"
}
Frame {
msec: 5888
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "7f788af35c7190d04bdc06cbf921c83d"
}
Frame {
msec: 5904
- hash: "b692386f34972d80aded2347e64ad2b6"
+ hash: "012078bb87950fdb960e2679a47c4bf6"
}
Frame {
msec: 5920
- hash: "dc65b0a791002efffec05884aa948842"
+ hash: "4fbcfc907361ccbe5ec5d945cb49065e"
}
Frame {
msec: 5936
- hash: "069bab78e29d322894647f81d315184a"
+ hash: "e450930da4d7838a2539a73bb3e8b9e3"
}
Frame {
msec: 5952
- hash: "39c8d804b3caf53845baba4ce98e007d"
+ hash: "d482896bddc89c4739674877be15972c"
}
Frame {
msec: 5968
- hash: "3b477dfd05f07bdf0ba562d6068cafdb"
+ hash: "9cf23658545ac1d744c6c549a86b561d"
}
Frame {
msec: 5984
- hash: "eb84ee75bdbf25dcc32587007f5dc9bd"
+ hash: "79eee90dbf4ba9992dca0e9e4ef02350"
}
Frame {
msec: 6000
- hash: "441d34bff2755e3c30bed80e2bdde69c"
+ hash: "cfc32ce2407a6d8a84fe99393c5d5d9e"
}
Frame {
msec: 6016
- hash: "4cb9ee1d12b99fb98bedcbcc048867e4"
+ hash: "af880ae1f0eb620a416cea66216f2509"
}
Frame {
msec: 6032
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "2268d0cb4b9a906339c310df870e0f2a"
}
Frame {
msec: 6048
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "d54aa3080e0d7d68cb30efdb2fbb3ff2"
}
Frame {
msec: 6064
- hash: "a0c46402b4700cc2099bdf42c47faf9b"
+ hash: "a53fba1a850cf0f3d1f8d6bc22ae2141"
}
Frame {
msec: 6080
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "64e241917730f914f3866d3bd3f6dc7f"
}
Frame {
msec: 6096
- hash: "c92cba3c2825db4293153588c4b7b229"
+ hash: "02aa690ffbecf879f7f98fecace8e0b6"
}
Frame {
msec: 6112
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "3ed37ab35b06f483b984014266bf59ea"
}
Frame {
msec: 6128
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "7f788af35c7190d04bdc06cbf921c83d"
}
Frame {
msec: 6144
- hash: "b692386f34972d80aded2347e64ad2b6"
+ hash: "012078bb87950fdb960e2679a47c4bf6"
}
Frame {
msec: 6160
- hash: "dc65b0a791002efffec05884aa948842"
+ hash: "4fbcfc907361ccbe5ec5d945cb49065e"
}
Frame {
msec: 6176
- hash: "069bab78e29d322894647f81d315184a"
+ hash: "e450930da4d7838a2539a73bb3e8b9e3"
}
Frame {
msec: 6192
- hash: "39c8d804b3caf53845baba4ce98e007d"
+ hash: "d482896bddc89c4739674877be15972c"
}
Frame {
msec: 6208
- hash: "3b477dfd05f07bdf0ba562d6068cafdb"
+ hash: "9cf23658545ac1d744c6c549a86b561d"
}
Frame {
msec: 6224
- hash: "eb84ee75bdbf25dcc32587007f5dc9bd"
+ hash: "79eee90dbf4ba9992dca0e9e4ef02350"
}
Frame {
msec: 6240
- hash: "441d34bff2755e3c30bed80e2bdde69c"
+ hash: "cfc32ce2407a6d8a84fe99393c5d5d9e"
}
Frame {
msec: 6256
- hash: "57e68ec2aa5a21b11d21f388399713e5"
+ hash: "377a5cd9be5f70975fe74d4de1bf2e70"
}
Frame {
msec: 6272
- hash: "4cb9ee1d12b99fb98bedcbcc048867e4"
+ hash: "af880ae1f0eb620a416cea66216f2509"
}
Frame {
msec: 6288
- hash: "3eebd1f4f58210f6b546715997a984c2"
+ hash: "a114b81c8856296087a26129724f9115"
}
Frame {
msec: 6304
- hash: "39eabc07bfcefb2ecd369abf94d706cd"
+ hash: "f989d9099072c32c619061b9cced2a85"
}
Frame {
msec: 6320
- hash: "a0c46402b4700cc2099bdf42c47faf9b"
+ hash: "774663163bef719b9656fbd78316c720"
}
Frame {
msec: 6336
- hash: "3c8b4831583922c7c1c85f227ef2b3dc"
+ hash: "36461d046d6df8b1f85997bc4090d537"
}
Frame {
msec: 6352
- hash: "c92cba3c2825db4293153588c4b7b229"
+ hash: "02aa690ffbecf879f7f98fecace8e0b6"
}
Frame {
msec: 6368
- hash: "e1b0d4cae609f3074fb1ac46c172bf4a"
+ hash: "3ed37ab35b06f483b984014266bf59ea"
}
Frame {
msec: 6384
- hash: "09b76db3e4a95666ba9c37dd89996fa3"
+ hash: "7f788af35c7190d04bdc06cbf921c83d"
}
}
diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/dynamic.qml b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/dynamic.qml
index b5685d1a9a..a1bb78f3ce 100644
--- a/tests/auto/declarative/qmlvisual/qdeclarativepositioners/dynamic.qml
+++ b/tests/auto/declarative/qmlvisual/qdeclarativepositioners/dynamic.qml
@@ -1,9 +1,9 @@
import QtQuick 1.0
Item {
- property string skip: "Expected to fail until QTBUG-14839 is resolved"
width: 120; height: 60;
property int step: 0
+ property int tickTime: 250;
function tick()
{
step++;
@@ -30,7 +30,7 @@ Item {
//Tests base positioner functionality, so don't need them all.
Column{
- move: Transition{NumberAnimation{properties:"y"}}
+ move: Transition{NumberAnimation{properties:"y"; duration: tickTime}}
Row{
id: row1
height: childrenRect.height
@@ -41,18 +41,19 @@ Item {
Row{
id: row2
height: childrenRect.height
- move: Transition{NumberAnimation{properties:"x"}}
+ move: Transition{NumberAnimation{properties:"x"; duration: tickTime}}
+ add: Transition{NumberAnimation{properties:"x"; duration: tickTime}}
Repeater{
id: repeater
model: 0;
- delegate: Component{ Rectangle { color: "yellow"; width:20; height:20;}}
+ delegate: Component{ Rectangle { color: "yellow"; x:20; width:20; height:20;}}
}
Rectangle{id: r2a; width:20; height:20; color: "red"}
Rectangle{id: r2b; width:20; height:20; color: "green"}
Rectangle{id: r2c; width:20; height:20; color: "blue"}
}
Row{
- move: Transition{NumberAnimation{properties:"x"}}
+ move: Transition{NumberAnimation{properties:"x"; duration: tickTime}}
id: row3
height: childrenRect.height
Rectangle{id: r3a; width:20; height:20; color: "red"}
@@ -61,7 +62,7 @@ Item {
}
}
Timer{
- interval: 250;
+ interval: tickTime;
running: true;
repeat: true;
onTriggered: tick();
diff --git a/tests/auto/declarative/qsganimatedimage/data/colors.gif b/tests/auto/declarative/qsganimatedimage/data/colors.gif
new file mode 100644
index 0000000000..1270bfaa79
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/colors.gif
Binary files differ
diff --git a/tests/auto/declarative/qsganimatedimage/data/colors.qml b/tests/auto/declarative/qsganimatedimage/data/colors.qml
new file mode 100644
index 0000000000..5ccc0148dd
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/colors.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+AnimatedImage {
+ source: "colors.gif"
+}
diff --git a/tests/auto/declarative/qsganimatedimage/data/hearts.gif b/tests/auto/declarative/qsganimatedimage/data/hearts.gif
new file mode 100644
index 0000000000..cfb55f27f5
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/hearts.gif
Binary files differ
diff --git a/tests/auto/declarative/qsganimatedimage/data/hearts.qml b/tests/auto/declarative/qsganimatedimage/data/hearts.qml
new file mode 100644
index 0000000000..717bab430b
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/hearts.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+AnimatedImage {
+ source: "hearts.gif"
+ playing: false
+}
diff --git a/tests/auto/declarative/qsganimatedimage/data/qmldir b/tests/auto/declarative/qsganimatedimage/data/qmldir
new file mode 100644
index 0000000000..ef7c1f44f3
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/qmldir
@@ -0,0 +1 @@
+# No local types
diff --git a/tests/auto/declarative/qsganimatedimage/data/qtbug-16520.qml b/tests/auto/declarative/qsganimatedimage/data/qtbug-16520.qml
new file mode 100644
index 0000000000..da77a4063b
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/qtbug-16520.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 500
+ height: 500
+
+ AnimatedImage {
+ objectName: "anim"
+ anchors.centerIn: parent
+ asynchronous: true
+ opacity: status == AnimatedImage.Ready ? 1 : 0
+
+ Behavior on opacity {
+ NumberAnimation { duration: 1000 }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsganimatedimage/data/stickman.gif b/tests/auto/declarative/qsganimatedimage/data/stickman.gif
new file mode 100644
index 0000000000..7c4cd18687
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/stickman.gif
Binary files differ
diff --git a/tests/auto/declarative/qsganimatedimage/data/stickman.qml b/tests/auto/declarative/qsganimatedimage/data/stickman.qml
new file mode 100644
index 0000000000..a47924de21
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/stickman.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+AnimatedImage {
+ source: "stickman.gif"
+}
diff --git a/tests/auto/declarative/qsganimatedimage/data/stickmanerror1.qml b/tests/auto/declarative/qsganimatedimage/data/stickmanerror1.qml
new file mode 100644
index 0000000000..4f823b3d70
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/stickmanerror1.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+AnimatedImage {
+ sourceSize: "240x180"
+ source: "stickman.gif"
+}
diff --git a/tests/auto/declarative/qsganimatedimage/data/stickmanpause.qml b/tests/auto/declarative/qsganimatedimage/data/stickmanpause.qml
new file mode 100644
index 0000000000..ef771ed56f
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/stickmanpause.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+AnimatedImage {
+ source: "stickman.gif"
+ paused: true
+ currentFrame: 2
+}
diff --git a/tests/auto/declarative/qsganimatedimage/data/stickmanscaled.qml b/tests/auto/declarative/qsganimatedimage/data/stickmanscaled.qml
new file mode 100644
index 0000000000..1ef1f95165
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/stickmanscaled.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+AnimatedImage {
+ width: 240
+ height: 180
+ source: "stickman.gif"
+}
diff --git a/tests/auto/declarative/qsganimatedimage/data/stickmanstopped.qml b/tests/auto/declarative/qsganimatedimage/data/stickmanstopped.qml
new file mode 100644
index 0000000000..0bf80b8972
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/data/stickmanstopped.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+AnimatedImage {
+ source: "stickman.gif"
+ playing: false
+}
diff --git a/tests/auto/declarative/qsganimatedimage/qsganimatedimage.pro b/tests/auto/declarative/qsganimatedimage/qsganimatedimage.pro
new file mode 100644
index 0000000000..f809c22074
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/qsganimatedimage.pro
@@ -0,0 +1,16 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative network
+HEADERS += ../shared/testhttpserver.h
+SOURCES += tst_qsganimatedimage.cpp ../shared/testhttpserver.cpp
+macx:CONFIG -= app_bundle
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsganimatedimage/tst_qsganimatedimage.cpp b/tests/auto/declarative/qsganimatedimage/tst_qsganimatedimage.cpp
new file mode 100644
index 0000000000..24f8cb6114
--- /dev/null
+++ b/tests/auto/declarative/qsganimatedimage/tst_qsganimatedimage.cpp
@@ -0,0 +1,387 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qsgview.h>
+#include <private/qsgrectangle_p.h>
+#include <private/qsgimage_p.h>
+#include <private/qsganimatedimage_p.h>
+#include <QSignalSpy>
+#include <QtDeclarative/qdeclarativecontext.h>
+
+#include "../shared/testhttpserver.h"
+#include "../../../shared/util.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_qsganimatedimage : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qsganimatedimage() {}
+
+private slots:
+ void play();
+ void pause();
+ void stopped();
+ void setFrame();
+ void frameCount();
+ void mirror_running();
+ void mirror_notRunning();
+ void mirror_notRunning_data();
+ void remote();
+ void remote_data();
+ void sourceSize();
+ void sourceSizeReadOnly();
+ void invalidSource();
+ void qtbug_16520();
+ void progressAndStatusChanges();
+
+private:
+ QPixmap grabScene(QGraphicsScene *scene, int width, int height);
+};
+
+QPixmap tst_qsganimatedimage::grabScene(QGraphicsScene *scene, int width, int height)
+{
+ QPixmap screenshot(width, height);
+ screenshot.fill();
+ QPainter p_screenshot(&screenshot);
+ scene->render(&p_screenshot, QRect(0, 0, width, height), QRect(0, 0, width, height));
+ return screenshot;
+}
+
+void tst_qsganimatedimage::play()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/stickman.qml"));
+ QSGAnimatedImage *anim = qobject_cast<QSGAnimatedImage *>(component.create());
+ QVERIFY(anim);
+ QVERIFY(anim->isPlaying());
+
+ delete anim;
+}
+
+void tst_qsganimatedimage::pause()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/stickmanpause.qml"));
+ QSGAnimatedImage *anim = qobject_cast<QSGAnimatedImage *>(component.create());
+ QVERIFY(anim);
+ QVERIFY(anim->isPlaying());
+ QVERIFY(anim->isPaused());
+
+ delete anim;
+}
+
+void tst_qsganimatedimage::stopped()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/stickmanstopped.qml"));
+ QSGAnimatedImage *anim = qobject_cast<QSGAnimatedImage *>(component.create());
+ QVERIFY(anim);
+ QVERIFY(!anim->isPlaying());
+ QCOMPARE(anim->currentFrame(), 0);
+
+ delete anim;
+}
+
+void tst_qsganimatedimage::setFrame()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/stickmanpause.qml"));
+ QSGAnimatedImage *anim = qobject_cast<QSGAnimatedImage *>(component.create());
+ QVERIFY(anim);
+ QVERIFY(anim->isPlaying());
+ QCOMPARE(anim->currentFrame(), 2);
+
+ delete anim;
+}
+
+void tst_qsganimatedimage::frameCount()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/colors.qml"));
+ QSGAnimatedImage *anim = qobject_cast<QSGAnimatedImage *>(component.create());
+ QVERIFY(anim);
+ QVERIFY(anim->isPlaying());
+ QCOMPARE(anim->frameCount(), 3);
+
+ delete anim;
+}
+
+void tst_qsganimatedimage::mirror_running()
+{
+ // test where mirror is set to true after animation has started
+
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/hearts.qml"));
+ QSGAnimatedImage *anim = qobject_cast<QSGAnimatedImage *>(component.create());
+ QVERIFY(anim);
+
+ QGraphicsScene scene;
+ int width = anim->property("width").toInt();
+ int height = anim->property("height").toInt();
+ scene.addItem(qobject_cast<QSGItem *>(anim));
+
+ QCOMPARE(anim->currentFrame(), 0);
+ QPixmap frame0 = grabScene(&scene, width, height);
+ anim->setCurrentFrame(1);
+ QPixmap frame1 = grabScene(&scene, width, height);
+
+ anim->setCurrentFrame(0);
+
+ QSignalSpy spy(anim, SIGNAL(frameChanged()));
+ anim->setPlaying(true);
+
+ QTRY_VERIFY(spy.count() == 1); spy.clear();
+ anim->setProperty("mirror", true);
+
+ QCOMPARE(anim->currentFrame(), 1);
+ QPixmap frame1_flipped = grabScene(&scene, width, height);
+
+ QTRY_VERIFY(spy.count() == 1); spy.clear();
+ QCOMPARE(anim->currentFrame(), 0); // animation only has 2 frames, should cycle back to first
+ QPixmap frame0_flipped = grabScene(&scene, width, height);
+
+ QTransform transform;
+ transform.translate(width, 0).scale(-1, 1.0);
+ QPixmap frame0_expected = frame0.transformed(transform);
+ QPixmap frame1_expected = frame1.transformed(transform);
+
+ QCOMPARE(frame0_flipped, frame0_expected);
+ QCOMPARE(frame1_flipped, frame1_expected);
+}
+
+void tst_qsganimatedimage::mirror_notRunning()
+{
+ QFETCH(QUrl, fileUrl);
+
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, fileUrl);
+ QSGAnimatedImage *anim = qobject_cast<QSGAnimatedImage *>(component.create());
+ QVERIFY(anim);
+
+ QGraphicsScene scene;
+ int width = anim->property("width").toInt();
+ int height = anim->property("height").toInt();
+ scene.addItem(qobject_cast<QSGItem *>(anim));
+ QPixmap screenshot = grabScene(&scene, width, height);
+
+ QTransform transform;
+ transform.translate(width, 0).scale(-1, 1.0);
+ QPixmap expected = screenshot.transformed(transform);
+
+ int frame = anim->currentFrame();
+ bool playing = anim->isPlaying();
+ bool paused = anim->isPlaying();
+
+ anim->setProperty("mirror", true);
+ screenshot = grabScene(&scene, width, height);
+
+ QCOMPARE(screenshot, expected);
+
+ // mirroring should not change the current frame or playing status
+ QCOMPARE(anim->currentFrame(), frame);
+ QCOMPARE(anim->isPlaying(), playing);
+ QCOMPARE(anim->isPaused(), paused);
+
+ delete anim;
+}
+
+void tst_qsganimatedimage::mirror_notRunning_data()
+{
+ QTest::addColumn<QUrl>("fileUrl");
+
+ QTest::newRow("paused") << QUrl::fromLocalFile(SRCDIR "/data/stickmanpause.qml");
+ QTest::newRow("stopped") << QUrl::fromLocalFile(SRCDIR "/data/stickmanstopped.qml");
+}
+
+void tst_qsganimatedimage::remote()
+{
+ QFETCH(QString, fileName);
+ QFETCH(bool, paused);
+
+ TestHTTPServer server(14449);
+ QVERIFY(server.isValid());
+ server.serveDirectory(SRCDIR "/data");
+
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("http://127.0.0.1:14449/" + fileName));
+ QTRY_VERIFY(component.isReady());
+
+ QSGAnimatedImage *anim = qobject_cast<QSGAnimatedImage *>(component.create());
+ QVERIFY(anim);
+
+ QTRY_VERIFY(anim->isPlaying());
+ if (paused) {
+ QTRY_VERIFY(anim->isPaused());
+ QCOMPARE(anim->currentFrame(), 2);
+ }
+ QVERIFY(anim->status() != QSGAnimatedImage::Error);
+
+ delete anim;
+}
+
+void tst_qsganimatedimage::sourceSize()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/stickmanscaled.qml"));
+ QSGAnimatedImage *anim = qobject_cast<QSGAnimatedImage *>(component.create());
+ QVERIFY(anim);
+ QCOMPARE(anim->width(),240.0);
+ QCOMPARE(anim->height(),180.0);
+ QCOMPARE(anim->sourceSize(),QSize(160,120));
+
+ delete anim;
+}
+
+void tst_qsganimatedimage::sourceSizeReadOnly()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/stickmanerror1.qml"));
+ QVERIFY(component.isError());
+ QCOMPARE(component.errors().at(0).description(), QString("Invalid property assignment: \"sourceSize\" is a read-only property"));
+}
+
+void tst_qsganimatedimage::remote_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<bool>("paused");
+
+ QTest::newRow("playing") << "stickman.qml" << false;
+ QTest::newRow("paused") << "stickmanpause.qml" << true;
+}
+
+void tst_qsganimatedimage::invalidSource()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 1.0\n AnimatedImage { source: \"no-such-file.gif\" }", QUrl::fromLocalFile(""));
+ QVERIFY(component.isReady());
+
+ QTest::ignoreMessage(QtWarningMsg, "file::2:2: QML AnimatedImage: Error Reading Animated Image File file:no-such-file.gif");
+
+ QSGAnimatedImage *anim = qobject_cast<QSGAnimatedImage *>(component.create());
+ QVERIFY(anim);
+
+ QVERIFY(!anim->isPlaying());
+ QVERIFY(!anim->isPaused());
+ QCOMPARE(anim->currentFrame(), 0);
+ QCOMPARE(anim->frameCount(), 0);
+ QTRY_VERIFY(anim->status() == 3);
+}
+
+void tst_qsganimatedimage::qtbug_16520()
+{
+ TestHTTPServer server(14449);
+ QVERIFY(server.isValid());
+ server.serveDirectory(SRCDIR "/data");
+
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/qtbug-16520.qml"));
+ QTRY_VERIFY(component.isReady());
+
+ QSGRectangle *root = qobject_cast<QSGRectangle *>(component.create());
+ QVERIFY(root);
+ QSGAnimatedImage *anim = root->findChild<QSGAnimatedImage*>("anim");
+
+ anim->setProperty("source", "http://127.0.0.1:14449/stickman.gif");
+
+ QTRY_VERIFY(anim->opacity() == 0);
+ QTRY_VERIFY(anim->opacity() == 1);
+
+ delete anim;
+}
+
+void tst_qsganimatedimage::progressAndStatusChanges()
+{
+ TestHTTPServer server(14449);
+ QVERIFY(server.isValid());
+ server.serveDirectory(SRCDIR "/data");
+
+ QDeclarativeEngine engine;
+ QString componentStr = "import QtQuick 1.0\nAnimatedImage { source: srcImage }";
+ QDeclarativeContext *ctxt = engine.rootContext();
+ ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/stickman.gif"));
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+ QVERIFY(obj->status() == QSGImage::Ready);
+ QTRY_VERIFY(obj->progress() == 1.0);
+
+ QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &)));
+ QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal)));
+ QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QSGImageBase::Status)));
+
+ // Loading local file
+ ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.gif"));
+ QTRY_VERIFY(obj->status() == QSGImage::Ready);
+ QTRY_VERIFY(obj->progress() == 1.0);
+ QTRY_COMPARE(sourceSpy.count(), 1);
+ QTRY_COMPARE(progressSpy.count(), 0);
+ QTRY_COMPARE(statusSpy.count(), 0);
+
+ // Loading remote file
+ ctxt->setContextProperty("srcImage", "http://127.0.0.1:14449/stickman.gif");
+ QTRY_VERIFY(obj->status() == QSGImage::Loading);
+ QTRY_VERIFY(obj->progress() == 0.0);
+ QTRY_VERIFY(obj->status() == QSGImage::Ready);
+ QTRY_VERIFY(obj->progress() == 1.0);
+ QTRY_COMPARE(sourceSpy.count(), 2);
+ QTRY_VERIFY(progressSpy.count() > 1);
+ QTRY_COMPARE(statusSpy.count(), 2);
+
+ ctxt->setContextProperty("srcImage", "");
+ QTRY_VERIFY(obj->status() == QSGImage::Null);
+ QTRY_VERIFY(obj->progress() == 0.0);
+ QTRY_COMPARE(sourceSpy.count(), 3);
+ QTRY_VERIFY(progressSpy.count() > 2);
+ QTRY_COMPARE(statusSpy.count(), 3);
+}
+
+QTEST_MAIN(tst_qsganimatedimage)
+
+#include "tst_qsganimatedimage.moc"
diff --git a/tests/auto/declarative/qsgborderimage/data/colors-round-remote.sci b/tests/auto/declarative/qsgborderimage/data/colors-round-remote.sci
new file mode 100644
index 0000000000..c673bed598
--- /dev/null
+++ b/tests/auto/declarative/qsgborderimage/data/colors-round-remote.sci
@@ -0,0 +1,7 @@
+border.left:10
+border.top:20
+border.right:30
+border.bottom:40
+horizontalTileRule:Round
+verticalTileRule:Repeat
+source:http://127.0.0.1:14446/colors.png
diff --git a/tests/auto/declarative/qsgborderimage/data/colors-round.sci b/tests/auto/declarative/qsgborderimage/data/colors-round.sci
new file mode 100644
index 0000000000..5d2f49f0e1
--- /dev/null
+++ b/tests/auto/declarative/qsgborderimage/data/colors-round.sci
@@ -0,0 +1,7 @@
+border.left:10
+border.top:20
+border.right:30
+border.bottom:40
+horizontalTileRule:Round
+verticalTileRule:Repeat
+source:colors.png
diff --git a/tests/auto/declarative/qsgborderimage/data/colors.png b/tests/auto/declarative/qsgborderimage/data/colors.png
new file mode 100644
index 0000000000..dfb62f3d64
--- /dev/null
+++ b/tests/auto/declarative/qsgborderimage/data/colors.png
Binary files differ
diff --git a/tests/auto/declarative/qsgborderimage/data/heart200.png b/tests/auto/declarative/qsgborderimage/data/heart200.png
new file mode 100644
index 0000000000..5a31ae8f4d
--- /dev/null
+++ b/tests/auto/declarative/qsgborderimage/data/heart200.png
Binary files differ
diff --git a/tests/auto/declarative/qsgborderimage/data/invalid.sci b/tests/auto/declarative/qsgborderimage/data/invalid.sci
new file mode 100644
index 0000000000..98c72c9bf1
--- /dev/null
+++ b/tests/auto/declarative/qsgborderimage/data/invalid.sci
@@ -0,0 +1,7 @@
+border.left:10
+border.top:20
+border.down:30
+border.up:40
+horizontalTileRule:Roun
+verticalTileRule:Repea
+source:colors.png
diff --git a/tests/auto/declarative/qsgborderimage/qsgborderimage.pro b/tests/auto/declarative/qsgborderimage/qsgborderimage.pro
new file mode 100644
index 0000000000..7bd8ca24cd
--- /dev/null
+++ b/tests/auto/declarative/qsgborderimage/qsgborderimage.pro
@@ -0,0 +1,17 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui network
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/testhttpserver.h
+SOURCES += tst_qsgborderimage.cpp ../shared/testhttpserver.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgborderimage/tst_qsgborderimage.cpp b/tests/auto/declarative/qsgborderimage/tst_qsgborderimage.cpp
new file mode 100644
index 0000000000..17b9305ac8
--- /dev/null
+++ b/tests/auto/declarative/qsgborderimage/tst_qsgborderimage.cpp
@@ -0,0 +1,426 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QTextDocument>
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QDir>
+#include <QGraphicsScene>
+#include <QPainter>
+
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <private/qsgborderimage_p.h>
+#include <private/qsgimagebase_p.h>
+#include <private/qsgscalegrid_p_p.h>
+#include <private/qsgloader_p.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+
+#include "../shared/testhttpserver.h"
+#include "../../../shared/util.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+#define SERVER_PORT 14446
+#define SERVER_ADDR "http://127.0.0.1:14446"
+
+class tst_qsgborderimage : public QObject
+
+{
+ Q_OBJECT
+public:
+ tst_qsgborderimage();
+
+private slots:
+ void noSource();
+ void imageSource();
+ void imageSource_data();
+ void clearSource();
+ void resized();
+ void smooth();
+ void mirror();
+ void tileModes();
+ void sciSource();
+ void sciSource_data();
+ void invalidSciFile();
+ void pendingRemoteRequest();
+ void pendingRemoteRequest_data();
+ void testQtQuick11Attributes();
+ void testQtQuick11Attributes_data();
+
+private:
+ QDeclarativeEngine engine;
+};
+
+tst_qsgborderimage::tst_qsgborderimage()
+{
+}
+
+void tst_qsgborderimage::noSource()
+{
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"\" }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->source(), QUrl());
+ QCOMPARE(obj->width(), 0.);
+ QCOMPARE(obj->height(), 0.);
+ QCOMPARE(obj->horizontalTileMode(), QSGBorderImage::Stretch);
+ QCOMPARE(obj->verticalTileMode(), QSGBorderImage::Stretch);
+
+ delete obj;
+}
+
+void tst_qsgborderimage::imageSource_data()
+{
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<bool>("remote");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("local") << QUrl::fromLocalFile(SRCDIR "/data/colors.png").toString() << false << "";
+ QTest::newRow("local not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString() << false
+ << "file::2:1: QML BorderImage: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString();
+ QTest::newRow("remote") << SERVER_ADDR "/colors.png" << true << "";
+ QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << true
+ << "file::2:1: QML BorderImage: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found";
+}
+
+void tst_qsgborderimage::imageSource()
+{
+ QFETCH(QString, source);
+ QFETCH(bool, remote);
+ QFETCH(QString, error);
+
+ TestHTTPServer *server = 0;
+ if (remote) {
+ server = new TestHTTPServer(SERVER_PORT);
+ QVERIFY(server->isValid());
+ server->serveDirectory(SRCDIR "/data");
+ }
+
+ if (!error.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
+
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"" + source + "\" }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+
+ if (remote)
+ QTRY_VERIFY(obj->status() == QSGBorderImage::Loading);
+
+ QCOMPARE(obj->source(), remote ? source : QUrl(source));
+
+ if (error.isEmpty()) {
+ QTRY_VERIFY(obj->status() == QSGBorderImage::Ready);
+ QCOMPARE(obj->width(), 120.);
+ QCOMPARE(obj->height(), 120.);
+ QCOMPARE(obj->sourceSize().width(), 120);
+ QCOMPARE(obj->sourceSize().height(), 120);
+ QCOMPARE(obj->horizontalTileMode(), QSGBorderImage::Stretch);
+ QCOMPARE(obj->verticalTileMode(), QSGBorderImage::Stretch);
+ } else {
+ QTRY_VERIFY(obj->status() == QSGBorderImage::Error);
+ }
+
+ delete obj;
+ delete server;
+}
+
+void tst_qsgborderimage::clearSource()
+{
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: srcImage }";
+ QDeclarativeContext *ctxt = engine.rootContext();
+ ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.png"));
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+ QVERIFY(obj->status() == QSGBorderImage::Ready);
+ QCOMPARE(obj->width(), 120.);
+ QCOMPARE(obj->height(), 120.);
+
+ ctxt->setContextProperty("srcImage", "");
+ QVERIFY(obj->source().isEmpty());
+ QVERIFY(obj->status() == QSGBorderImage::Null);
+ QCOMPARE(obj->width(), 0.);
+ QCOMPARE(obj->height(), 0.);
+}
+
+void tst_qsgborderimage::resized()
+{
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"" + QUrl::fromLocalFile(SRCDIR "/data/colors.png").toString() + "\"; width: 300; height: 300 }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->width(), 300.);
+ QCOMPARE(obj->height(), 300.);
+ QCOMPARE(obj->sourceSize().width(), 120);
+ QCOMPARE(obj->sourceSize().height(), 120);
+ QCOMPARE(obj->horizontalTileMode(), QSGBorderImage::Stretch);
+ QCOMPARE(obj->verticalTileMode(), QSGBorderImage::Stretch);
+
+ delete obj;
+}
+
+void tst_qsgborderimage::smooth()
+{
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; smooth: true; width: 300; height: 300 }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->width(), 300.);
+ QCOMPARE(obj->height(), 300.);
+ QCOMPARE(obj->smooth(), true);
+ QCOMPARE(obj->horizontalTileMode(), QSGBorderImage::Stretch);
+ QCOMPARE(obj->verticalTileMode(), QSGBorderImage::Stretch);
+
+ delete obj;
+}
+
+void tst_qsgborderimage::mirror()
+{
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"" SRCDIR "/data/heart200.png\"; smooth: true; width: 300; height: 300; border { top: 50; right: 50; bottom: 50; left: 50 } }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+
+ int width = obj->property("width").toInt();
+ int height = obj->property("height").toInt();
+
+ QGraphicsScene scene;
+ scene.addItem(qobject_cast<QSGItem *>(obj));
+ QPixmap screenshot(width, height);
+ screenshot.fill();
+ QPainter p_screenshot(&screenshot);
+ scene.render(&p_screenshot, QRect(0, 0, width, height), QRect(0, 0, width, height));
+
+ QTransform transform;
+ transform.translate(width, 0).scale(-1, 1.0);
+ QPixmap expected = screenshot.transformed(transform);
+
+ obj->setProperty("mirror", true);
+ p_screenshot.fillRect(QRect(0, 0, width, height), Qt::white);
+ scene.render(&p_screenshot, QRect(0, 0, width, height), QRect(0, 0, width, height));
+
+ QCOMPARE(screenshot, expected);
+
+ delete obj;
+}
+
+void tst_qsgborderimage::tileModes()
+{
+ {
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; width: 100; height: 300; horizontalTileMode: BorderImage.Repeat; verticalTileMode: BorderImage.Repeat }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->width(), 100.);
+ QCOMPARE(obj->height(), 300.);
+ QCOMPARE(obj->horizontalTileMode(), QSGBorderImage::Repeat);
+ QCOMPARE(obj->verticalTileMode(), QSGBorderImage::Repeat);
+
+ delete obj;
+ }
+ {
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; width: 300; height: 150; horizontalTileMode: BorderImage.Round; verticalTileMode: BorderImage.Round }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->width(), 300.);
+ QCOMPARE(obj->height(), 150.);
+ QCOMPARE(obj->horizontalTileMode(), QSGBorderImage::Round);
+ QCOMPARE(obj->verticalTileMode(), QSGBorderImage::Round);
+
+ delete obj;
+ }
+}
+
+void tst_qsgborderimage::sciSource()
+{
+ QFETCH(QString, source);
+ QFETCH(bool, valid);
+
+ bool remote = source.startsWith("http");
+ TestHTTPServer *server = 0;
+ if (remote) {
+ server = new TestHTTPServer(SERVER_PORT);
+ QVERIFY(server->isValid());
+ server->serveDirectory(SRCDIR "/data");
+ }
+
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"" + source + "\"; width: 300; height: 300 }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+
+ if (remote)
+ QTRY_VERIFY(obj->status() == QSGBorderImage::Loading);
+
+ QCOMPARE(obj->source(), remote ? source : QUrl(source));
+ QCOMPARE(obj->width(), 300.);
+ QCOMPARE(obj->height(), 300.);
+
+ if (valid) {
+ QTRY_VERIFY(obj->status() == QSGBorderImage::Ready);
+ QCOMPARE(obj->border()->left(), 10);
+ QCOMPARE(obj->border()->top(), 20);
+ QCOMPARE(obj->border()->right(), 30);
+ QCOMPARE(obj->border()->bottom(), 40);
+ QCOMPARE(obj->horizontalTileMode(), QSGBorderImage::Round);
+ QCOMPARE(obj->verticalTileMode(), QSGBorderImage::Repeat);
+ } else {
+ QTRY_VERIFY(obj->status() == QSGBorderImage::Error);
+ }
+
+ delete obj;
+ delete server;
+}
+
+void tst_qsgborderimage::sciSource_data()
+{
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<bool>("valid");
+
+ QTest::newRow("local") << QUrl::fromLocalFile(SRCDIR "/data/colors-round.sci").toString() << true;
+ QTest::newRow("local not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file.sci").toString() << false;
+ QTest::newRow("remote") << SERVER_ADDR "/colors-round.sci" << true;
+ QTest::newRow("remote image") << SERVER_ADDR "/colors-round-remote.sci" << true;
+ QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.sci" << false;
+}
+
+void tst_qsgborderimage::invalidSciFile()
+{
+ QTest::ignoreMessage(QtWarningMsg, "QSGGridScaledImage: Invalid tile rule specified. Using Stretch."); // for "Roun"
+ QTest::ignoreMessage(QtWarningMsg, "QSGGridScaledImage: Invalid tile rule specified. Using Stretch."); // for "Repea"
+
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"" + QUrl::fromLocalFile(SRCDIR "/data/invalid.sci").toString() +"\"; width: 300; height: 300 }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->width(), 300.);
+ QCOMPARE(obj->height(), 300.);
+ QCOMPARE(obj->status(), QSGImageBase::Error);
+ QCOMPARE(obj->horizontalTileMode(), QSGBorderImage::Stretch);
+ QCOMPARE(obj->verticalTileMode(), QSGBorderImage::Stretch);
+
+ delete obj;
+}
+
+void tst_qsgborderimage::pendingRemoteRequest()
+{
+ QFETCH(QString, source);
+
+ QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"" + source + "\" }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGBorderImage *obj = qobject_cast<QSGBorderImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->status(), QSGBorderImage::Loading);
+
+ // verify no crash
+ // This will cause a delayed "QThread: Destroyed while thread is still running" warning
+ delete obj;
+ QTest::qWait(50);
+}
+
+void tst_qsgborderimage::pendingRemoteRequest_data()
+{
+ QTest::addColumn<QString>("source");
+
+ QTest::newRow("png file") << "http://localhost/none.png";
+ QTest::newRow("sci file") << "http://localhost/none.sci";
+}
+
+void tst_qsgborderimage::testQtQuick11Attributes()
+{
+ QFETCH(QString, code);
+ QFETCH(QString, warning);
+ QFETCH(QString, error);
+
+ QDeclarativeEngine engine;
+ QObject *obj;
+
+ QDeclarativeComponent valid(&engine);
+ valid.setData("import QtQuick 1.1; BorderImage { " + code.toUtf8() + " }", QUrl(""));
+ obj = valid.create();
+ QVERIFY(obj);
+ QVERIFY(valid.errorString().isEmpty());
+ delete obj;
+
+ QDeclarativeComponent invalid(&engine);
+ invalid.setData("import QtQuick 1.0; BorderImage { " + code.toUtf8() + " }", QUrl(""));
+ QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
+ obj = invalid.create();
+ QCOMPARE(invalid.errorString(), error);
+ delete obj;
+}
+
+void tst_qsgborderimage::testQtQuick11Attributes_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("mirror") << "mirror: true"
+ << "QDeclarativeComponent: Component is not ready"
+ << ":1 \"BorderImage.mirror\" is not available in QtQuick 1.0.\n";
+
+ QTest::newRow("cache") << "cache: true"
+ << "QDeclarativeComponent: Component is not ready"
+ << ":1 \"BorderImage.cache\" is not available in QtQuick 1.0.\n";
+}
+
+QTEST_MAIN(tst_qsgborderimage)
+
+#include "tst_qsgborderimage.moc"
diff --git a/tests/auto/declarative/qsgcanvas/qsgcanvas.pro b/tests/auto/declarative/qsgcanvas/qsgcanvas.pro
new file mode 100644
index 0000000000..126c10b017
--- /dev/null
+++ b/tests/auto/declarative/qsgcanvas/qsgcanvas.pro
@@ -0,0 +1,7 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative
+SOURCES += tst_qsgcanvas.cpp
+
+macx:CONFIG -= app_bundle
+
+CONFIG += parallel_test
diff --git a/tests/auto/declarative/qsgcanvas/tst_qsgcanvas.cpp b/tests/auto/declarative/qsgcanvas/tst_qsgcanvas.cpp
new file mode 100644
index 0000000000..68552bf88a
--- /dev/null
+++ b/tests/auto/declarative/qsgcanvas/tst_qsgcanvas.cpp
@@ -0,0 +1,437 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QDebug>
+#include <QTouchEvent>
+
+#include "qsgitem.h"
+#include "qsgcanvas.h"
+#include "private/qsgrectangle_p.h"
+#include "../../../shared/util.h"
+
+struct TouchEventData {
+ QEvent::Type type;
+ QWidget *widget;
+ Qt::TouchPointStates states;
+ QList<QTouchEvent::TouchPoint> touchPoints;
+};
+
+static QTouchEvent::TouchPoint makeTouchPoint(QSGItem *item, const QPointF &p, const QPointF &lastPoint = QPointF())
+{
+ QPointF last = lastPoint.isNull() ? p : lastPoint;
+
+ QTouchEvent::TouchPoint tp;
+ tp.setPos(p);
+ tp.setLastPos(last);
+ tp.setScenePos(item->mapToScene(p));
+ tp.setLastScenePos(item->mapToScene(last));
+ tp.setScreenPos(item->canvas()->mapToGlobal(tp.scenePos().toPoint()));
+ tp.setLastScreenPos(item->canvas()->mapToGlobal(tp.lastScenePos().toPoint()));
+ return tp;
+}
+
+static TouchEventData makeTouchData(QEvent::Type type, QWidget *w, Qt::TouchPointStates states, const QList<QTouchEvent::TouchPoint> &touchPoints)
+{
+ TouchEventData d = { type, w, states, touchPoints };
+ return d;
+}
+
+static TouchEventData makeTouchData(QEvent::Type type, QWidget *w, Qt::TouchPointStates states, const QTouchEvent::TouchPoint &touchPoint)
+{
+ QList<QTouchEvent::TouchPoint> points;
+ points << touchPoint;
+ return makeTouchData(type, w, states, points);
+}
+
+#define COMPARE_TOUCH_POINTS(tp1, tp2) \
+{ \
+ QCOMPARE(tp1.pos(), tp2.pos()); \
+ QCOMPARE(tp1.lastPos(), tp2.lastPos()); \
+ QCOMPARE(tp1.scenePos(), tp2.scenePos()); \
+ QCOMPARE(tp1.lastScenePos(), tp2.lastScenePos()); \
+ QCOMPARE(tp1.screenPos(), tp2.screenPos()); \
+ QCOMPARE(tp1.lastScreenPos(), tp2.lastScreenPos()); \
+}
+
+#define COMPARE_TOUCH_DATA(d1, d2) \
+{ \
+ QCOMPARE((int)d1.type, (int)d2.type); \
+ QCOMPARE(d1.widget, d2.widget); \
+ QCOMPARE((int)d1.states, (int)d2.states); \
+ QCOMPARE(d1.touchPoints.count(), d2.touchPoints.count()); \
+ for (int i=0; i<d1.touchPoints.count(); i++) { \
+ COMPARE_TOUCH_POINTS(d1.touchPoints[i], d2.touchPoints[i]); \
+ } \
+}
+
+class TestTouchItem : public QSGRectangle
+{
+ Q_OBJECT
+public:
+ TestTouchItem(QSGItem *parent = 0)
+ : QSGRectangle(parent), acceptEvents(true)
+ {
+ border()->setWidth(1);
+ }
+
+ void reset() {
+ acceptEvents = true;
+ setEnabled(true);
+ setOpacity(1.0);
+
+ lastEvent = makeTouchData(QEvent::None, 0, 0, QList<QTouchEvent::TouchPoint>());
+ }
+
+ bool acceptEvents;
+ TouchEventData lastEvent;
+
+protected:
+ virtual void touchEvent(QTouchEvent *event) {
+ if (!acceptEvents) {
+ event->ignore();
+ return;
+ }
+ lastEvent = makeTouchData(event->type(), event->widget(), event->touchPointStates(), event->touchPoints());
+ event->accept();
+ }
+};
+
+
+class ConstantUpdateItem : public QSGItem
+{
+Q_OBJECT
+public:
+ ConstantUpdateItem(QSGItem *parent = 0) : QSGItem(parent), iterations(0) {setFlag(ItemHasContents);}
+
+ int iterations;
+protected:
+ QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *){
+ iterations++;
+ update();
+ return 0;
+ }
+};
+
+class tst_qsgcanvas : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qsgcanvas();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void constantUpdates();
+
+ void touchEvent_basic();
+ void touchEvent_propagation();
+ void touchEvent_propagation_data();
+
+ void clearCanvas();
+};
+
+tst_qsgcanvas::tst_qsgcanvas()
+{
+}
+
+void tst_qsgcanvas::initTestCase()
+{
+}
+
+void tst_qsgcanvas::cleanupTestCase()
+{
+}
+
+//If the item calls update inside updatePaintNode, it should schedule another update
+void tst_qsgcanvas::constantUpdates()
+{
+ QSGCanvas canvas;
+ ConstantUpdateItem item(canvas.rootItem());
+ canvas.show();
+ QTRY_VERIFY(item.iterations > 60);
+}
+
+void tst_qsgcanvas::touchEvent_basic()
+{
+ QSGCanvas *canvas = new QSGCanvas;
+ canvas->resize(250, 250);
+ canvas->window()->move(100, 100);
+ canvas->show();
+
+ TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
+ bottomItem->setObjectName("Bottom Item");
+ bottomItem->setSize(QSizeF(150, 150));
+
+ TestTouchItem *middleItem = new TestTouchItem(bottomItem);
+ middleItem->setObjectName("Middle Item");
+ middleItem->setPos(QPointF(50, 50));
+ middleItem->setSize(QSizeF(150, 150));
+
+ TestTouchItem *topItem = new TestTouchItem(middleItem);
+ topItem->setObjectName("Top Item");
+ topItem->setPos(QPointF(50, 50));
+ topItem->setSize(QSizeF(150, 150));
+
+ QPointF pos(10, 10);
+
+ // press single point
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint());
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
+ topItem->reset();
+
+ // press multiple points
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint())
+ .press(1, bottomItem->mapToScene(pos).toPoint());
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
+ topItem->reset();
+ bottomItem->reset();
+
+ // touch point on top item moves to bottom item, but top item should still receive the event
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).move(0, bottomItem->mapToScene(pos).toPoint());
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, canvas, Qt::TouchPointMoved,
+ makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
+ topItem->reset();
+
+ // touch point on bottom item moves to top item, but bottom item should still receive the event
+ QTest::touchEvent(canvas).press(0, bottomItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).move(0, topItem->mapToScene(pos).toPoint());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, canvas, Qt::TouchPointMoved,
+ makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos)));
+ bottomItem->reset();
+
+ // a single stationary press on an item shouldn't cause an event
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).stationary(0)
+ .press(1, bottomItem->mapToScene(pos).toPoint());
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); // received press only, not stationary
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
+ topItem->reset();
+ bottomItem->reset();
+
+ // move touch point from top item to bottom, and release
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).release(0, bottomItem->mapToScene(pos).toPoint());
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, canvas, Qt::TouchPointReleased,
+ makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
+ topItem->reset();
+
+ // release while another point is pressed
+ QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint())
+ .press(1, bottomItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).move(0, bottomItem->mapToScene(pos).toPoint());
+ QTest::touchEvent(canvas).release(0, bottomItem->mapToScene(pos).toPoint())
+ .stationary(1);
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, canvas, Qt::TouchPointReleased,
+ makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos))));
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
+ topItem->reset();
+ bottomItem->reset();
+
+ delete topItem;
+ delete middleItem;
+ delete bottomItem;
+ delete canvas;
+}
+
+void tst_qsgcanvas::touchEvent_propagation()
+{
+ QFETCH(bool, acceptEvents);
+ QFETCH(bool, enableItem);
+ QFETCH(qreal, itemOpacity);
+
+ QSGCanvas *canvas = new QSGCanvas;
+ canvas->resize(250, 250);
+ canvas->window()->move(100, 100);
+ canvas->show();
+
+ TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
+ bottomItem->setObjectName("Bottom Item");
+ bottomItem->setSize(QSizeF(150, 150));
+
+ TestTouchItem *middleItem = new TestTouchItem(bottomItem);
+ middleItem->setObjectName("Middle Item");
+ middleItem->setPos(QPointF(50, 50));
+ middleItem->setSize(QSizeF(150, 150));
+
+ TestTouchItem *topItem = new TestTouchItem(middleItem);
+ topItem->setObjectName("Top Item");
+ topItem->setPos(QPointF(50, 50));
+ topItem->setSize(QSizeF(150, 150));
+
+ QPointF pos(10, 10);
+ QPoint pointInBottomItem = bottomItem->mapToScene(pos).toPoint(); // (10, 10)
+ QPoint pointInMiddleItem = middleItem->mapToScene(pos).toPoint(); // (60, 60) overlaps with bottomItem
+ QPoint pointInTopItem = topItem->mapToScene(pos).toPoint(); // (110, 110) overlaps with bottom & top items
+
+ // disable topItem
+ topItem->acceptEvents = acceptEvents;
+ topItem->setEnabled(enableItem);
+ topItem->setOpacity(itemOpacity);
+
+ // single touch to top item, should be received by middle item
+ QTest::touchEvent(canvas).press(0, pointInTopItem);
+ QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(middleItem->lastEvent.touchPoints.count(), 1);
+ QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
+ COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
+ makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))));
+
+ // touch top and middle items, middle item should get both events
+ QTest::touchEvent(canvas).press(0, pointInTopItem)
+ .press(1, pointInMiddleItem);
+ QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(middleItem->lastEvent.touchPoints.count(), 2);
+ QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
+ COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
+ (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))
+ << makeTouchPoint(middleItem, pos) )));
+ middleItem->reset();
+
+ // disable middleItem as well
+ middleItem->acceptEvents = acceptEvents;
+ middleItem->setEnabled(enableItem);
+ middleItem->setOpacity(itemOpacity);
+
+ // touch top and middle items, bottom item should get all events
+ QTest::touchEvent(canvas).press(0, pointInTopItem)
+ .press(1, pointInMiddleItem);
+ QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 2);
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
+ (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))
+ << makeTouchPoint(bottomItem, bottomItem->mapFromItem(middleItem, pos)) )));
+ bottomItem->reset();
+
+ // disable bottom item as well
+ bottomItem->acceptEvents = acceptEvents;
+ bottomItem->setEnabled(enableItem);
+ bottomItem->setOpacity(itemOpacity);
+
+ // no events should be received
+ QTest::touchEvent(canvas).press(0, pointInTopItem)
+ .press(1, pointInMiddleItem)
+ .press(2, pointInBottomItem);
+ QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
+
+ topItem->reset();
+ middleItem->reset();
+ bottomItem->reset();
+
+ // disable middle item, touch on top item
+ middleItem->acceptEvents = acceptEvents;
+ middleItem->setEnabled(enableItem);
+ middleItem->setOpacity(itemOpacity);
+ QTest::touchEvent(canvas).press(0, pointInTopItem);
+ if (!enableItem || itemOpacity == 0) {
+ // middle item is disabled or has 0 opacity, bottom item receives the event
+ QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
+ makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))));
+ } else {
+ // middle item ignores event, sends it to the top item (top-most child)
+ QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
+ QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
+ COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
+ makeTouchPoint(topItem, pos)));
+ }
+
+ delete topItem;
+ delete middleItem;
+ delete bottomItem;
+ delete canvas;
+}
+
+void tst_qsgcanvas::touchEvent_propagation_data()
+{
+ QTest::addColumn<bool>("acceptEvents");
+ QTest::addColumn<bool>("enableItem");
+ QTest::addColumn<qreal>("itemOpacity");
+
+ QTest::newRow("disable events") << false << true << 1.0;
+ QTest::newRow("disable item") << true << false << 1.0;
+ QTest::newRow("opacity of 0") << true << true << 0.0;
+}
+
+void tst_qsgcanvas::clearCanvas()
+{
+ QSGCanvas *canvas = new QSGCanvas;
+ QSGItem *item = new QSGItem;
+ item->setParentItem(canvas->rootItem());
+
+ QVERIFY(item->canvas() == canvas);
+
+ delete canvas;
+
+ QVERIFY(item->canvas() == 0);
+
+ delete item;
+}
+
+
+
+QTEST_MAIN(tst_qsgcanvas)
+
+#include "tst_qsgcanvas.moc"
diff --git a/tests/auto/declarative/qsgflickable/data/disabledcontent.qml b/tests/auto/declarative/qsgflickable/data/disabledcontent.qml
new file mode 100644
index 0000000000..f02f08e4ea
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/data/disabledcontent.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Flickable {
+ width: 100; height: 100
+ contentWidth: 200; contentHeight: 300
+
+ QGraphicsWidget { width: 200; height: 300; enabled: false }
+}
diff --git a/tests/auto/declarative/qsgflickable/data/flickable01.qml b/tests/auto/declarative/qsgflickable/data/flickable01.qml
new file mode 100644
index 0000000000..cbec44bb4f
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/data/flickable01.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.0
+
+Flickable {
+}
diff --git a/tests/auto/declarative/qsgflickable/data/flickable02.qml b/tests/auto/declarative/qsgflickable/data/flickable02.qml
new file mode 100644
index 0000000000..80caa32da5
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/data/flickable02.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Flickable {
+ width: 100; height: 100
+ contentWidth: row.width; contentHeight: row.height
+
+ Row {
+ id: row
+ Repeater {
+ model: 4
+ Rectangle { width: 200; height: 300; color: "blue" }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgflickable/data/flickable03.qml b/tests/auto/declarative/qsgflickable/data/flickable03.qml
new file mode 100644
index 0000000000..e34b63b6ac
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/data/flickable03.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Flickable {
+ width: 100; height: 100
+ contentWidth: column.width; contentHeight: column.height
+
+ Column {
+ id: column
+ Repeater {
+ model: 4
+ Rectangle { width: 200; height: 300; color: "blue" }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgflickable/data/flickable04.qml b/tests/auto/declarative/qsgflickable/data/flickable04.qml
new file mode 100644
index 0000000000..b2f30b84ec
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/data/flickable04.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+
+Flickable {
+ property bool ok: false
+ function check() {
+ if (column.parent == contentItem)
+ ok = true;
+ }
+
+ width: 100; height: 100
+ contentWidth: column.width; contentHeight: column.height
+ pressDelay: 200; boundsBehavior: Flickable.StopAtBounds; interactive: false
+ maximumFlickVelocity: 2000
+
+ Column {
+ id: column
+ Repeater {
+ model: 4
+ Rectangle { width: 200; height: 300; color: "blue" }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgflickable/data/flickableqgraphicswidget.qml b/tests/auto/declarative/qsgflickable/data/flickableqgraphicswidget.qml
new file mode 100644
index 0000000000..bb8f1eefc6
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/data/flickableqgraphicswidget.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Flickable {
+ width: 100; height: 100
+
+ QGraphicsWidget { objectName: "widget1"; width: 200; height: 300 }
+}
diff --git a/tests/auto/declarative/qsgflickable/data/nestedPressDelay.qml b/tests/auto/declarative/qsgflickable/data/nestedPressDelay.qml
new file mode 100644
index 0000000000..60dadcc73c
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/data/nestedPressDelay.qml
@@ -0,0 +1,33 @@
+import QtQuick 2.0
+
+Flickable {
+ property bool pressed: ma.pressed
+ width: 240
+ height: 320
+ contentWidth: 480
+ contentHeight: 320
+ flickableDirection: Flickable.HorizontalFlick
+ pressDelay: 50
+ Flickable {
+ objectName: "innerFlickable"
+ flickableDirection: Flickable.VerticalFlick
+ width: 480
+ height: 320
+ contentWidth: 480
+ contentHeight: 400
+ pressDelay: 10000
+ Rectangle {
+ y: 100
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: 240
+ height: 100
+ color: ma.pressed ? 'blue' : 'green'
+ MouseArea {
+ id: ma
+ objectName: "mouseArea"
+ anchors.fill: parent
+ }
+ }
+ }
+}
+
diff --git a/tests/auto/declarative/qsgflickable/data/resize.qml b/tests/auto/declarative/qsgflickable/data/resize.qml
new file mode 100644
index 0000000000..1a9ef54107
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/data/resize.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+Rectangle {
+ function resizeContent() {
+ flick.resizeContent(600, 600, Qt.point(100, 100))
+ }
+ function returnToBounds() {
+ flick.returnToBounds()
+ }
+ width: 400
+ height: 360
+ color: "gray"
+
+ Flickable {
+ id: flick
+ objectName: "flick"
+ anchors.fill: parent
+ contentWidth: 300
+ contentHeight: 300
+
+ Rectangle {
+ width: flick.contentWidth
+ height: flick.contentHeight
+ color: "red"
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgflickable/data/wheel.qml b/tests/auto/declarative/qsgflickable/data/wheel.qml
new file mode 100644
index 0000000000..2928bbcd72
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/data/wheel.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 400
+ color: "gray"
+
+ Flickable {
+ id: flick
+ objectName: "flick"
+ anchors.fill: parent
+ contentWidth: 800
+ contentHeight: 800
+
+ Rectangle {
+ width: flick.contentWidth
+ height: flick.contentHeight
+ color: "red"
+ Rectangle {
+ width: 50; height: 50; color: "blue"
+ anchors.centerIn: parent
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgflickable/qsgflickable.pro b/tests/auto/declarative/qsgflickable/qsgflickable.pro
new file mode 100644
index 0000000000..a1ecbe509a
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/qsgflickable.pro
@@ -0,0 +1,16 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qsgflickable.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgflickable/tst_qsgflickable.cpp b/tests/auto/declarative/qsgflickable/tst_qsgflickable.cpp
new file mode 100644
index 0000000000..1532281338
--- /dev/null
+++ b/tests/auto/declarative/qsgflickable/tst_qsgflickable.cpp
@@ -0,0 +1,450 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtTest/QSignalSpy>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qsgview.h>
+#include <private/qsgflickable_p.h>
+#include <private/qdeclarativevaluetype_p.h>
+#include <math.h>
+#include "../../../shared/util.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_qsgflickable : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qsgflickable();
+
+private slots:
+ void create();
+ void horizontalViewportSize();
+ void verticalViewportSize();
+ void properties();
+ void boundsBehavior();
+ void maximumFlickVelocity();
+ void flickDeceleration();
+ void pressDelay();
+ void disabledContent();
+ void nestedPressDelay();
+ void flickableDirection();
+ void resizeContent();
+ void returnToBounds();
+ void wheel();
+
+private:
+ QDeclarativeEngine engine;
+
+ template<typename T>
+ T *findItem(QSGItem *parent, const QString &objectName);
+};
+
+tst_qsgflickable::tst_qsgflickable()
+{
+}
+
+void tst_qsgflickable::create()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable01.qml"));
+ QSGFlickable *obj = qobject_cast<QSGFlickable*>(c.create());
+
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->isAtXBeginning(), true);
+ QCOMPARE(obj->isAtXEnd(), false);
+ QCOMPARE(obj->isAtYBeginning(), true);
+ QCOMPARE(obj->isAtYEnd(), false);
+ QCOMPARE(obj->contentX(), 0.);
+ QCOMPARE(obj->contentY(), 0.);
+
+ QCOMPARE(obj->horizontalVelocity(), 0.);
+ QCOMPARE(obj->verticalVelocity(), 0.);
+
+ QCOMPARE(obj->isInteractive(), true);
+ QCOMPARE(obj->boundsBehavior(), QSGFlickable::DragAndOvershootBounds);
+ QCOMPARE(obj->pressDelay(), 0);
+ QCOMPARE(obj->maximumFlickVelocity(), 2000.);
+
+ delete obj;
+}
+
+void tst_qsgflickable::horizontalViewportSize()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable02.qml"));
+ QSGFlickable *obj = qobject_cast<QSGFlickable*>(c.create());
+
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->contentWidth(), 800.);
+ QCOMPARE(obj->contentHeight(), 300.);
+ QCOMPARE(obj->isAtXBeginning(), true);
+ QCOMPARE(obj->isAtXEnd(), false);
+ QCOMPARE(obj->isAtYBeginning(), true);
+ QCOMPARE(obj->isAtYEnd(), false);
+
+ delete obj;
+}
+
+void tst_qsgflickable::verticalViewportSize()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable03.qml"));
+ QSGFlickable *obj = qobject_cast<QSGFlickable*>(c.create());
+
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->contentWidth(), 200.);
+ QCOMPARE(obj->contentHeight(), 1200.);
+ QCOMPARE(obj->isAtXBeginning(), true);
+ QCOMPARE(obj->isAtXEnd(), false);
+ QCOMPARE(obj->isAtYBeginning(), true);
+ QCOMPARE(obj->isAtYEnd(), false);
+
+ delete obj;
+}
+
+void tst_qsgflickable::properties()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable04.qml"));
+ QSGFlickable *obj = qobject_cast<QSGFlickable*>(c.create());
+
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->isInteractive(), false);
+ QCOMPARE(obj->boundsBehavior(), QSGFlickable::StopAtBounds);
+ QCOMPARE(obj->pressDelay(), 200);
+ QCOMPARE(obj->maximumFlickVelocity(), 2000.);
+
+ QVERIFY(obj->property("ok").toBool() == false);
+ QMetaObject::invokeMethod(obj, "check");
+ QVERIFY(obj->property("ok").toBool() == true);
+
+ delete obj;
+}
+
+void tst_qsgflickable::boundsBehavior()
+{
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 2.0; Flickable { boundsBehavior: Flickable.StopAtBounds }", QUrl::fromLocalFile(""));
+ QSGFlickable *flickable = qobject_cast<QSGFlickable*>(component.create());
+ QSignalSpy spy(flickable, SIGNAL(boundsBehaviorChanged()));
+
+ QVERIFY(flickable);
+ QVERIFY(flickable->boundsBehavior() == QSGFlickable::StopAtBounds);
+
+ flickable->setBoundsBehavior(QSGFlickable::DragAndOvershootBounds);
+ QVERIFY(flickable->boundsBehavior() == QSGFlickable::DragAndOvershootBounds);
+ QCOMPARE(spy.count(),1);
+ flickable->setBoundsBehavior(QSGFlickable::DragAndOvershootBounds);
+ QCOMPARE(spy.count(),1);
+
+ flickable->setBoundsBehavior(QSGFlickable::DragOverBounds);
+ QVERIFY(flickable->boundsBehavior() == QSGFlickable::DragOverBounds);
+ QCOMPARE(spy.count(),2);
+ flickable->setBoundsBehavior(QSGFlickable::DragOverBounds);
+ QCOMPARE(spy.count(),2);
+
+ flickable->setBoundsBehavior(QSGFlickable::StopAtBounds);
+ QVERIFY(flickable->boundsBehavior() == QSGFlickable::StopAtBounds);
+ QCOMPARE(spy.count(),3);
+ flickable->setBoundsBehavior(QSGFlickable::StopAtBounds);
+ QCOMPARE(spy.count(),3);
+}
+
+void tst_qsgflickable::maximumFlickVelocity()
+{
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 2.0; Flickable { maximumFlickVelocity: 1.0; }", QUrl::fromLocalFile(""));
+ QSGFlickable *flickable = qobject_cast<QSGFlickable*>(component.create());
+ QSignalSpy spy(flickable, SIGNAL(maximumFlickVelocityChanged()));
+
+ QVERIFY(flickable);
+ QCOMPARE(flickable->maximumFlickVelocity(), 1.0);
+
+ flickable->setMaximumFlickVelocity(2.0);
+ QCOMPARE(flickable->maximumFlickVelocity(), 2.0);
+ QCOMPARE(spy.count(),1);
+ flickable->setMaximumFlickVelocity(2.0);
+ QCOMPARE(spy.count(),1);
+}
+
+void tst_qsgflickable::flickDeceleration()
+{
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 2.0; Flickable { flickDeceleration: 1.0; }", QUrl::fromLocalFile(""));
+ QSGFlickable *flickable = qobject_cast<QSGFlickable*>(component.create());
+ QSignalSpy spy(flickable, SIGNAL(flickDecelerationChanged()));
+
+ QVERIFY(flickable);
+ QCOMPARE(flickable->flickDeceleration(), 1.0);
+
+ flickable->setFlickDeceleration(2.0);
+ QCOMPARE(flickable->flickDeceleration(), 2.0);
+ QCOMPARE(spy.count(),1);
+ flickable->setFlickDeceleration(2.0);
+ QCOMPARE(spy.count(),1);
+}
+
+void tst_qsgflickable::pressDelay()
+{
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 2.0; Flickable { pressDelay: 100; }", QUrl::fromLocalFile(""));
+ QSGFlickable *flickable = qobject_cast<QSGFlickable*>(component.create());
+ QSignalSpy spy(flickable, SIGNAL(pressDelayChanged()));
+
+ QVERIFY(flickable);
+ QCOMPARE(flickable->pressDelay(), 100);
+
+ flickable->setPressDelay(200);
+ QCOMPARE(flickable->pressDelay(), 200);
+ QCOMPARE(spy.count(),1);
+ flickable->setPressDelay(200);
+ QCOMPARE(spy.count(),1);
+}
+
+// QT-4677
+void tst_qsgflickable::disabledContent()
+{
+ QSGView *canvas = new QSGView;
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/disabledcontent.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGFlickable *flickable = qobject_cast<QSGFlickable*>(canvas->rootObject());
+ QVERIFY(flickable != 0);
+
+ QVERIFY(flickable->contentX() == 0);
+ QVERIFY(flickable->contentY() == 0);
+
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 50));
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(70,70), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(canvas, &mv);
+ }
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(90,90), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(canvas, &mv);
+ }
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(100,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(canvas, &mv);
+ }
+
+ QVERIFY(flickable->contentX() < 0);
+ QVERIFY(flickable->contentY() < 0);
+
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(90, 90));
+
+ delete canvas;
+}
+
+
+// QTBUG-17361
+void tst_qsgflickable::nestedPressDelay()
+{
+ QSGView *canvas = new QSGView;
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/nestedPressDelay.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGFlickable *outer = qobject_cast<QSGFlickable*>(canvas->rootObject());
+ QVERIFY(outer != 0);
+
+ QSGFlickable *inner = canvas->rootObject()->findChild<QSGFlickable*>("innerFlickable");
+ QVERIFY(inner != 0);
+
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(150, 150));
+ // the MouseArea is not pressed immediately
+ QVERIFY(outer->property("pressed").toBool() == false);
+
+ // The outer pressDelay will prevail (50ms, vs. 10sec)
+ // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec.
+ QTRY_VERIFY(outer->property("pressed").toBool() == true);
+
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(150, 150));
+
+ delete canvas;
+}
+
+void tst_qsgflickable::flickableDirection()
+{
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 2.0; Flickable { flickableDirection: Flickable.VerticalFlick; }", QUrl::fromLocalFile(""));
+ QSGFlickable *flickable = qobject_cast<QSGFlickable*>(component.create());
+ QSignalSpy spy(flickable, SIGNAL(flickableDirectionChanged()));
+
+ QVERIFY(flickable);
+ QCOMPARE(flickable->flickableDirection(), QSGFlickable::VerticalFlick);
+
+ flickable->setFlickableDirection(QSGFlickable::HorizontalAndVerticalFlick);
+ QCOMPARE(flickable->flickableDirection(), QSGFlickable::HorizontalAndVerticalFlick);
+ QCOMPARE(spy.count(),1);
+
+ flickable->setFlickableDirection(QSGFlickable::AutoFlickDirection);
+ QCOMPARE(flickable->flickableDirection(), QSGFlickable::AutoFlickDirection);
+ QCOMPARE(spy.count(),2);
+
+ flickable->setFlickableDirection(QSGFlickable::HorizontalFlick);
+ QCOMPARE(flickable->flickableDirection(), QSGFlickable::HorizontalFlick);
+ QCOMPARE(spy.count(),3);
+
+ flickable->setFlickableDirection(QSGFlickable::HorizontalFlick);
+ QCOMPARE(flickable->flickableDirection(), QSGFlickable::HorizontalFlick);
+ QCOMPARE(spy.count(),3);
+}
+
+// QtQuick 1.1
+void tst_qsgflickable::resizeContent()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/resize.qml"));
+ QSGItem *root = qobject_cast<QSGItem*>(c.create());
+ QSGFlickable *obj = findItem<QSGFlickable>(root, "flick");
+
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->contentX(), 0.);
+ QCOMPARE(obj->contentY(), 0.);
+ QCOMPARE(obj->contentWidth(), 300.);
+ QCOMPARE(obj->contentHeight(), 300.);
+
+ QMetaObject::invokeMethod(root, "resizeContent");
+
+ QCOMPARE(obj->contentX(), 100.);
+ QCOMPARE(obj->contentY(), 100.);
+ QCOMPARE(obj->contentWidth(), 600.);
+ QCOMPARE(obj->contentHeight(), 600.);
+
+ delete root;
+}
+
+// QtQuick 1.1
+void tst_qsgflickable::returnToBounds()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/resize.qml"));
+ QSGItem *root = qobject_cast<QSGItem*>(c.create());
+ QSGFlickable *obj = findItem<QSGFlickable>(root, "flick");
+
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->contentX(), 0.);
+ QCOMPARE(obj->contentY(), 0.);
+ QCOMPARE(obj->contentWidth(), 300.);
+ QCOMPARE(obj->contentHeight(), 300.);
+
+ obj->setContentX(100);
+ obj->setContentY(400);
+ QTRY_COMPARE(obj->contentX(), 100.);
+ QTRY_COMPARE(obj->contentY(), 400.);
+
+ QMetaObject::invokeMethod(root, "returnToBounds");
+
+ QTRY_COMPARE(obj->contentX(), 0.);
+ QTRY_COMPARE(obj->contentY(), 0.);
+
+ delete root;
+}
+
+void tst_qsgflickable::wheel()
+{
+ QSGView *canvas = new QSGView;
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/wheel.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGFlickable *flick = canvas->rootObject()->findChild<QSGFlickable*>("flick");
+ QVERIFY(flick != 0);
+
+ {
+ QWheelEvent event(QPoint(200, 200), -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical);
+ event.setAccepted(false);
+ QApplication::sendEvent(canvas, &event);
+ }
+
+ QTRY_VERIFY(flick->contentY() > 0);
+ QVERIFY(flick->contentX() == 0);
+
+ flick->setContentY(0);
+ QVERIFY(flick->contentY() == 0);
+
+ {
+ QWheelEvent event(QPoint(200, 200), -120, Qt::NoButton, Qt::NoModifier, Qt::Horizontal);
+ event.setAccepted(false);
+ QApplication::sendEvent(canvas, &event);
+ }
+
+ QTRY_VERIFY(flick->contentX() > 0);
+ QVERIFY(flick->contentY() == 0);
+
+ delete canvas;
+}
+
+
+template<typename T>
+T *tst_qsgflickable::findItem(QSGItem *parent, const QString &objectName)
+{
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->childItems().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ return static_cast<T*>(item);
+ }
+ item = findItem<T>(item, objectName);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+}
+
+QTEST_MAIN(tst_qsgflickable)
+
+#include "tst_qsgflickable.moc"
diff --git a/tests/auto/declarative/qsgflipable/data/crash.qml b/tests/auto/declarative/qsgflipable/data/crash.qml
new file mode 100644
index 0000000000..a0327918cb
--- /dev/null
+++ b/tests/auto/declarative/qsgflipable/data/crash.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Flipable {
+ transform: Rotation {
+ axis.y: 1
+ axis.z: 0
+ angle: 180
+ }
+}
diff --git a/tests/auto/declarative/qsgflipable/data/flipable-abort.qml b/tests/auto/declarative/qsgflipable/data/flipable-abort.qml
new file mode 100644
index 0000000000..90fc03a5f9
--- /dev/null
+++ b/tests/auto/declarative/qsgflipable/data/flipable-abort.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+Rectangle {
+ Flipable {
+ id: flipable
+ }
+ Rectangle {
+ visible: flipable.side == Flipable.Front
+ }
+}
diff --git a/tests/auto/declarative/qsgflipable/data/test-flipable.qml b/tests/auto/declarative/qsgflipable/data/test-flipable.qml
new file mode 100644
index 0000000000..dff6d3fe39
--- /dev/null
+++ b/tests/auto/declarative/qsgflipable/data/test-flipable.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Flipable {
+ id: flipable
+ width: 640; height: 480
+
+ front: Rectangle { anchors.fill: flipable }
+ back: Rectangle { anchors.fill: flipable }
+}
diff --git a/tests/auto/declarative/qsgflipable/qsgflipable.pro b/tests/auto/declarative/qsgflipable/qsgflipable.pro
new file mode 100644
index 0000000000..c87cd4db5c
--- /dev/null
+++ b/tests/auto/declarative/qsgflipable/qsgflipable.pro
@@ -0,0 +1,16 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qsgflipable.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgflipable/tst_qsgflipable.cpp b/tests/auto/declarative/qsgflipable/tst_qsgflipable.cpp
new file mode 100644
index 0000000000..205c2ce607
--- /dev/null
+++ b/tests/auto/declarative/qsgflipable/tst_qsgflipable.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qsgview.h>
+#include <private/qsgflipable_p.h>
+#include <private/qdeclarativevaluetype_p.h>
+#include <QFontMetrics>
+#include <private/qsgrectangle_p.h>
+#include <math.h>
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_qsgflipable : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qsgflipable();
+
+private slots:
+ void create();
+ void checkFrontAndBack();
+ void setFrontAndBack();
+
+ // below here task issues
+ void QTBUG_9161_crash();
+ void QTBUG_8474_qgv_abort();
+
+private:
+ QDeclarativeEngine engine;
+};
+
+tst_qsgflipable::tst_qsgflipable()
+{
+}
+
+void tst_qsgflipable::create()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/test-flipable.qml"));
+ QSGFlipable *obj = qobject_cast<QSGFlipable*>(c.create());
+
+ QVERIFY(obj != 0);
+ delete obj;
+}
+
+void tst_qsgflipable::checkFrontAndBack()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/test-flipable.qml"));
+ QSGFlipable *obj = qobject_cast<QSGFlipable*>(c.create());
+
+ QVERIFY(obj != 0);
+ QVERIFY(obj->front() != 0);
+ QVERIFY(obj->back() != 0);
+ delete obj;
+}
+
+void tst_qsgflipable::setFrontAndBack()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/test-flipable.qml"));
+ QSGFlipable *obj = qobject_cast<QSGFlipable*>(c.create());
+
+ QVERIFY(obj != 0);
+ QVERIFY(obj->front() != 0);
+ QVERIFY(obj->back() != 0);
+
+ QString message = c.url().toString() + ":3:1: QML Flipable: front is a write-once property";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
+ obj->setFront(new QSGRectangle());
+
+ message = c.url().toString() + ":3:1: QML Flipable: back is a write-once property";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
+ obj->setBack(new QSGRectangle());
+ delete obj;
+}
+
+void tst_qsgflipable::QTBUG_9161_crash()
+{
+ QSGView *canvas = new QSGView;
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/crash.qml"));
+ QSGItem *root = canvas->rootObject();
+ QVERIFY(root != 0);
+ canvas->show();
+ delete canvas;
+}
+
+void tst_qsgflipable::QTBUG_8474_qgv_abort()
+{
+ QSGView *canvas = new QSGView;
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/flipable-abort.qml"));
+ QSGItem *root = canvas->rootObject();
+ QVERIFY(root != 0);
+ canvas->show();
+ delete canvas;
+}
+
+QTEST_MAIN(tst_qsgflipable)
+
+#include "tst_qsgflipable.moc"
diff --git a/tests/auto/declarative/qsgfocusscope/data/chain.qml b/tests/auto/declarative/qsgfocusscope/data/chain.qml
new file mode 100644
index 0000000000..4b96662318
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/data/chain.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width:300; height:400
+
+ property bool focus1: root.activeFocus
+ property bool focus2: item1.activeFocus
+ property bool focus3: fs1.activeFocus
+ property bool focus4: fs2.activeFocus
+ property bool focus5: theItem.activeFocus
+
+ Item {
+ id: item1
+ FocusScope {
+ id: fs1
+ focus: true
+ FocusScope {
+ id: fs2
+ focus: true
+ Item {
+ id: theItem
+ focus: true
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgfocusscope/data/forceActiveFocus.qml b/tests/auto/declarative/qsgfocusscope/data/forceActiveFocus.qml
new file mode 100644
index 0000000000..74d2106888
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/data/forceActiveFocus.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+
+Rectangle {
+ objectName: "root"
+ FocusScope {
+ objectName: "scope"
+ Item {
+ objectName: "item-a1"
+ FocusScope {
+ objectName: "scope-a"
+ Item {
+ objectName: "item-a2"
+ }
+ }
+ }
+ Item {
+ objectName: "item-b1"
+ FocusScope {
+ objectName: "scope-b"
+ Item {
+ objectName: "item-b2"
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgfocusscope/data/forcefocus.qml b/tests/auto/declarative/qsgfocusscope/data/forcefocus.qml
new file mode 100644
index 0000000000..f41582a951
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/data/forcefocus.qml
@@ -0,0 +1,81 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 800; height: 600
+
+ FocusScope {
+ focus: true
+
+ FocusScope {
+ id: firstScope
+ objectName: "item0"
+ focus: true
+
+ Rectangle {
+ height: 120; width: 420
+
+ color: "transparent"
+ border.width: 5; border.color: firstScope.activeFocus?"blue":"black"
+
+ Rectangle {
+ id: item1; objectName: "item1"
+ x: 10; y: 10; width: 100; height: 100; color: "green"
+ border.width: 5; border.color: activeFocus?"blue":"black"
+ focus: true
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+
+ Rectangle {
+ id: item2; objectName: "item2"
+ x: 310; y: 10; width: 100; height: 100; color: "green"
+ border.width: 5; border.color: activeFocus?"blue":"black"
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+ }
+ }
+
+ FocusScope {
+ id: secondScope
+ objectName: "item3"
+
+ Rectangle {
+ y: 160; height: 120; width: 420
+
+ color: "transparent"
+ border.width: 5; border.color: secondScope.activeFocus?"blue":"black"
+
+ Rectangle {
+ id: item4; objectName: "item4"
+ x: 10; y: 10; width: 100; height: 100; color: "green"
+ border.width: 5; border.color: activeFocus?"blue":"black"
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+
+ Rectangle {
+ id: item5; objectName: "item5"
+ x: 310; y: 10; width: 100; height: 100; color: "green"
+ border.width: 5; border.color: activeFocus?"blue":"black"
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+ }
+ }
+ }
+ Keys.onDigit4Pressed: item4.focus = true
+ Keys.onDigit5Pressed: item5.forceActiveFocus()
+}
diff --git a/tests/auto/declarative/qsgfocusscope/data/qtBug13380.qml b/tests/auto/declarative/qsgfocusscope/data/qtBug13380.qml
new file mode 100644
index 0000000000..29de046b38
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/data/qtBug13380.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 400; height: 400
+
+ property bool showRect: false
+ onShowRectChanged: if (showRect) rect.visible = true
+ property bool noFocus: !fs2.activeFocus
+
+ FocusScope {
+ id: fs1
+ focus: true
+ }
+ Rectangle {
+ id: rect
+ visible: false
+ FocusScope {
+ id: fs2
+ Rectangle {
+ focus: true
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgfocusscope/data/signalEmission.qml b/tests/auto/declarative/qsgfocusscope/data/signalEmission.qml
new file mode 100644
index 0000000000..999a40c5ad
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/data/signalEmission.qml
@@ -0,0 +1,33 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 200
+ height: 200
+
+ FocusScope {
+ focus: true
+ Rectangle {
+ objectName: "item1"
+ color: "blue"
+ onFocusChanged: focus ? color = "red" : color = "blue"
+ }
+ Rectangle {
+ objectName: "item2"
+ color: "blue"
+ onFocusChanged: focus ? color = "red" : color = "blue"
+ }
+ }
+
+ FocusScope {
+ Rectangle {
+ objectName: "item3"
+ color: "blue"
+ onFocusChanged: focus ? color = "red" : color = "blue"
+ }
+ Rectangle {
+ objectName: "item4"
+ color: "blue"
+ onFocusChanged: focus ? color = "red" : color = "blue"
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgfocusscope/data/test.qml b/tests/auto/declarative/qsgfocusscope/data/test.qml
new file mode 100644
index 0000000000..67be29c3fb
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/data/test.qml
@@ -0,0 +1,77 @@
+import QtQuick 2.0
+
+Rectangle {
+ color: "white"
+ width: 800
+ height: 600
+
+ Keys.onDigit9Pressed: console.log("Error - Root")
+
+ FocusScope {
+ id: myScope
+ objectName: "item0"
+ focus: true
+
+ Keys.onDigit9Pressed: console.log("Error - FocusScope")
+
+ Rectangle {
+ height: 120
+ width: 420
+
+ color: "transparent"
+ border.width: 5
+ border.color: myScope.activeFocus?"blue":"black"
+
+ Rectangle {
+ id: item1; objectName: "item1"
+ x: 10; y: 10
+ width: 100; height: 100; color: "green"
+ border.width: 5
+ border.color: activeFocus?"blue":"black"
+ Keys.onDigit9Pressed: console.debug("Top Left");
+ KeyNavigation.right: item2
+ focus: true
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+
+ Rectangle {
+ id: item2; objectName: "item2"
+ x: 310; y: 10
+ width: 100; height: 100; color: "green"
+ border.width: 5
+ border.color: activeFocus?"blue":"black"
+ KeyNavigation.left: item1
+ Keys.onDigit9Pressed: console.log("Top Right");
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+ }
+ KeyNavigation.down: item3
+ }
+
+ Text { x:100; y:170; text: "Blue border indicates scoped focus\nBlack border indicates NOT scoped focus\nRed box indicates active focus\nUse arrow keys to navigate\nPress \"9\" to print currently focused item" }
+
+ Rectangle {
+ id: item3; objectName: "item3"
+ x: 10; y: 300
+ width: 100; height: 100; color: "green"
+ border.width: 5
+ border.color: activeFocus?"blue":"black"
+
+ Keys.onDigit9Pressed: console.log("Bottom Left");
+ KeyNavigation.up: myScope
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+
+}
diff --git a/tests/auto/declarative/qsgfocusscope/data/test2.qml b/tests/auto/declarative/qsgfocusscope/data/test2.qml
new file mode 100644
index 0000000000..ad74f3e9f4
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/data/test2.qml
@@ -0,0 +1,39 @@
+import QtQuick 2.0
+
+Rectangle {
+ color: "white"
+ width: 800
+ height: 600
+
+ Text { text: "All five rectangles should be red" }
+
+ FocusScope {
+ y: 100
+ focus: true; objectName: "item1"
+ Rectangle { width: 50; height: 50; color: parent.activeFocus?"red":"blue" }
+
+ FocusScope {
+ y: 100
+ focus: true; objectName: "item2"
+ Rectangle { width: 50; height: 50; color: parent.activeFocus?"red":"blue" }
+
+ FocusScope {
+ y: 100
+ focus: true; objectName: "item3"
+ Rectangle { width: 50; height: 50; color: parent.activeFocus?"red":"blue" }
+
+ FocusScope {
+ y: 100
+ focus: true; objectName: "item4"
+ Rectangle { width: 50; height: 50; color: parent.activeFocus?"red":"blue" }
+
+ FocusScope {
+ y: 100
+ focus: true; objectName: "item5"
+ Rectangle { width: 50; height: 50; color: parent.activeFocus?"red":"blue" }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgfocusscope/data/test3.qml b/tests/auto/declarative/qsgfocusscope/data/test3.qml
new file mode 100644
index 0000000000..537c30816e
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/data/test3.qml
@@ -0,0 +1,52 @@
+import QtQuick 2.0
+
+Rectangle {
+ color: "white"
+ width: 800
+ height: 600
+
+ ListModel {
+ id: model
+ ListElement { name: "1" }
+ ListElement { name: "2" }
+ ListElement { name: "3" }
+ ListElement { name: "4" }
+ ListElement { name: "5" }
+ ListElement { name: "6" }
+ ListElement { name: "7" }
+ ListElement { name: "8" }
+ ListElement { name: "9" }
+ }
+
+ Component {
+ id: verticalDelegate
+ FocusScope {
+ id: root
+ width: 50; height: 50;
+ Keys.onDigit9Pressed: console.log("Error - " + name)
+ Rectangle {
+ focus: true
+ Keys.onDigit9Pressed: console.log(name)
+ width: 50; height: 50;
+ color: root.ListView.isCurrentItem?"red":"green"
+ Text { text: name; anchors.centerIn: parent }
+ }
+ }
+ }
+
+ ListView {
+ width: 800; height: 50; orientation: "Horizontal"
+ focus: true
+ model: model
+ delegate: verticalDelegate
+ preferredHighlightBegin: 100
+ preferredHighlightEnd: 100
+ highlightRangeMode: "StrictlyEnforceRange"
+ }
+
+
+ Text {
+ y: 100; x: 50
+ text: "Currently selected element should be red\nPressing \"9\" should print the number of the currently selected item\nBe sure to scroll all the way to the right, pause, and then all the way to the left."
+ }
+}
diff --git a/tests/auto/declarative/qsgfocusscope/data/test4.qml b/tests/auto/declarative/qsgfocusscope/data/test4.qml
new file mode 100644
index 0000000000..0eea649f5d
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/data/test4.qml
@@ -0,0 +1,76 @@
+import QtQuick 2.0
+
+Rectangle {
+ color: "white"
+ width: 800
+ height: 600
+
+ Keys.onDigit9Pressed: console.log("Error - Root")
+
+ FocusScope {
+ id: myScope
+
+ Keys.onDigit9Pressed: console.log("Error - FocusScope")
+
+ Rectangle {
+ objectName: "item0"
+ height: 120
+ width: 420
+
+ color: "transparent"
+ border.width: 5
+ border.color: myScope.activeFocus?"blue":"black"
+
+ Rectangle {
+ id: item1; objectName: "item1"
+ x: 10; y: 10
+ width: 100; height: 100; color: "green"
+ border.width: 5
+ border.color: activeFocus?"blue":"black"
+ Keys.onDigit9Pressed: console.log("Error - Top Left");
+ KeyNavigation.right: item2
+ focus: true
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+
+ Rectangle {
+ id: item2; objectName: "item2"
+ x: 310; y: 10
+ width: 100; height: 100; color: "green"
+ border.width: 5
+ border.color: activeFocus?"blue":"black"
+ KeyNavigation.left: item1
+ Keys.onDigit9Pressed: console.log("Error - Top Right");
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+ }
+ KeyNavigation.down: item3
+ }
+
+ Text { x:100; y:170; text: "There should be no blue borders, or red squares.\nPressing \"9\" should do nothing.\nArrow keys should have no effect." }
+
+ Rectangle {
+ id: item3; objectName: "item3"
+ x: 10; y: 300
+ width: 100; height: 100; color: "green"
+ border.width: 5
+ border.color: activeFocus?"blue":"black"
+
+ Keys.onDigit9Pressed: console.log("Error - Bottom Left");
+ KeyNavigation.up: myScope
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+
+}
diff --git a/tests/auto/declarative/qsgfocusscope/data/test5.qml b/tests/auto/declarative/qsgfocusscope/data/test5.qml
new file mode 100644
index 0000000000..9c37cd1303
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/data/test5.qml
@@ -0,0 +1,84 @@
+import QtQuick 2.0
+
+Rectangle {
+ color: "white"
+ width: 800
+ height: 600
+
+ Keys.onReturnPressed: console.log("Error - Root")
+
+ FocusScope {
+ id: myScope
+ objectName: "item0"
+ focus: true
+
+ Keys.onReturnPressed: console.log("Error - FocusScope")
+
+ Rectangle {
+ height: 120
+ width: 420
+
+ color: "transparent"
+ border.width: 5
+ border.color: myScope.activeFocus?"blue":"black"
+
+ Rectangle {
+ x: 10; y: 10
+ width: 100; height: 100; color: "green"
+ border.width: 5
+ border.color: item1.activeFocus?"blue":"black"
+ }
+
+ TextEdit {
+ id: item1; objectName: "item1"
+ x: 20; y: 20
+ width: 90; height: 90
+ color: "white"
+ font.pixelSize: 20
+ Keys.onReturnPressed: console.log("Top Left");
+ KeyNavigation.right: item2
+ focus: true
+ wrapMode: TextEdit.WordWrap
+ text: "Box 1"
+ }
+
+ Rectangle {
+ id: item2; objectName: "item2"
+ x: 310; y: 10
+ width: 100; height: 100; color: "green"
+ border.width: 5
+ border.color: activeFocus?"blue":"black"
+ KeyNavigation.left: item1
+ Keys.onReturnPressed: console.log("Top Right");
+
+ Rectangle {
+ width: 50; height: 50; anchors.centerIn: parent
+ color: parent.activeFocus?"red":"transparent"
+ }
+ }
+ }
+ KeyNavigation.down: item3
+ }
+
+ Text { x:100; y:170; text: "Blue border indicates scoped focus\nBlack border indicates NOT scoped focus\nRed box or flashing cursor indicates active focus\nUse arrow keys to navigate\nPress Ctrl-Return to print currently focused item" }
+
+ Rectangle {
+ x: 10; y: 300
+ width: 100; height: 100; color: "green"
+ border.width: 5
+ border.color: item3.activeFocus?"blue":"black"
+ }
+
+ TextEdit {
+ id: item3; objectName: "item3"
+ x: 20; y: 310
+ width: 90; height: 90
+ color: "white"
+ font.pixelSize: 20
+ text: "Box 3"
+
+ Keys.onReturnPressed: console.log("Bottom Left");
+ KeyNavigation.up: myScope
+ wrapMode: TextEdit.WordWrap
+ }
+}
diff --git a/tests/auto/declarative/qsgfocusscope/qsgfocusscope.pro b/tests/auto/declarative/qsgfocusscope/qsgfocusscope.pro
new file mode 100644
index 0000000000..b34d1dbf74
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/qsgfocusscope.pro
@@ -0,0 +1,13 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative
+SOURCES += tst_qsgfocusscope.cpp
+macx:CONFIG -= app_bundle
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
diff --git a/tests/auto/declarative/qsgfocusscope/tst_qsgfocusscope.cpp b/tests/auto/declarative/qsgfocusscope/tst_qsgfocusscope.cpp
new file mode 100644
index 0000000000..c793ce91c5
--- /dev/null
+++ b/tests/auto/declarative/qsgfocusscope/tst_qsgfocusscope.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QSignalSpy>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qsgview.h>
+#include <private/qsgrectangle_p.h>
+#include <private/qsgtextedit_p.h>
+#include <private/qsgtext_p.h>
+#include <QtDeclarative/private/qsgfocusscope_p.h>
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_qsgfocusscope : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qsgfocusscope() {}
+
+ template<typename T>
+ T *findItem(QSGItem *parent, const QString &id);
+
+private slots:
+ void basic();
+ void nested();
+ void noFocus();
+ void textEdit();
+ void forceFocus();
+ void noParentFocus();
+ void signalEmission();
+ void qtBug13380();
+ void forceActiveFocus();
+};
+
+/*
+ Find an item with the specified id.
+*/
+template<typename T>
+T *tst_qsgfocusscope::findItem(QSGItem *parent, const QString &objectName)
+{
+ const QMetaObject &mo = T::staticMetaObject;
+ QList<QSGItem *> children = parent->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QSGItem *item = children.at(i);
+ if (item) {
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ return static_cast<T*>(item);
+ }
+ item = findItem<T>(item, objectName);
+ if (item)
+ return static_cast<T*>(item);
+ }
+ }
+ return 0;
+}
+
+void tst_qsgfocusscope::basic()
+{
+ QSGView *view = new QSGView;
+ view->setSource(QUrl::fromLocalFile(SRCDIR "/data/test.qml"));
+
+ QSGFocusScope *item0 = findItem<QSGFocusScope>(view->rootObject(), QLatin1String("item0"));
+ QSGRectangle *item1 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item1"));
+ QSGRectangle *item2 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item2"));
+ QSGRectangle *item3 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item3"));
+ QVERIFY(item0 != 0);
+ QVERIFY(item1 != 0);
+ QVERIFY(item2 != 0);
+ QVERIFY(item3 != 0);
+
+ view->show();
+ qApp->setActiveWindow(view);
+ qApp->processEvents();
+
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(view);
+#endif
+
+ QVERIFY(view->hasFocus());
+ QVERIFY(item0->hasActiveFocus() == true);
+ QVERIFY(item1->hasActiveFocus() == true);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == false);
+
+ QTest::keyClick(view, Qt::Key_Right);
+ QVERIFY(item0->hasActiveFocus() == true);
+ QVERIFY(item1->hasActiveFocus() == false);
+ QVERIFY(item2->hasActiveFocus() == true);
+ QVERIFY(item3->hasActiveFocus() == false);
+
+ QTest::keyClick(view, Qt::Key_Down);
+ QVERIFY(item0->hasActiveFocus() == false);
+ QVERIFY(item1->hasActiveFocus() == false);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == true);
+
+ delete view;
+}
+
+void tst_qsgfocusscope::nested()
+{
+ QSGView *view = new QSGView;
+ view->setSource(QUrl::fromLocalFile(SRCDIR "/data/test2.qml"));
+
+ QSGFocusScope *item1 = findItem<QSGFocusScope>(view->rootObject(), QLatin1String("item1"));
+ QSGFocusScope *item2 = findItem<QSGFocusScope>(view->rootObject(), QLatin1String("item2"));
+ QSGFocusScope *item3 = findItem<QSGFocusScope>(view->rootObject(), QLatin1String("item3"));
+ QSGFocusScope *item4 = findItem<QSGFocusScope>(view->rootObject(), QLatin1String("item4"));
+ QSGFocusScope *item5 = findItem<QSGFocusScope>(view->rootObject(), QLatin1String("item5"));
+ QVERIFY(item1 != 0);
+ QVERIFY(item2 != 0);
+ QVERIFY(item3 != 0);
+ QVERIFY(item4 != 0);
+ QVERIFY(item5 != 0);
+
+ view->show();
+ qApp->setActiveWindow(view);
+ qApp->processEvents();
+
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(view);
+#endif
+
+ QVERIFY(view->hasFocus());
+
+ QVERIFY(item1->hasActiveFocus() == true);
+ QVERIFY(item2->hasActiveFocus() == true);
+ QVERIFY(item3->hasActiveFocus() == true);
+ QVERIFY(item4->hasActiveFocus() == true);
+ QVERIFY(item5->hasActiveFocus() == true);
+ delete view;
+}
+
+void tst_qsgfocusscope::noFocus()
+{
+ QSGView *view = new QSGView;
+ view->setSource(QUrl::fromLocalFile(SRCDIR "/data/test4.qml"));
+
+ QSGRectangle *item0 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item0"));
+ QSGRectangle *item1 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item1"));
+ QSGRectangle *item2 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item2"));
+ QSGRectangle *item3 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item3"));
+ QVERIFY(item0 != 0);
+ QVERIFY(item1 != 0);
+ QVERIFY(item2 != 0);
+ QVERIFY(item3 != 0);
+
+ view->show();
+ qApp->setActiveWindow(view);
+ qApp->processEvents();
+
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(view);
+#endif
+
+ QVERIFY(view->hasFocus());
+ QVERIFY(item0->hasActiveFocus() == false);
+ QVERIFY(item1->hasActiveFocus() == false);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == false);
+
+ QTest::keyClick(view, Qt::Key_Right);
+ QVERIFY(item0->hasActiveFocus() == false);
+ QVERIFY(item1->hasActiveFocus() == false);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == false);
+
+ QTest::keyClick(view, Qt::Key_Down);
+ QVERIFY(item0->hasActiveFocus() == false);
+ QVERIFY(item1->hasActiveFocus() == false);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == false);
+
+ delete view;
+}
+
+void tst_qsgfocusscope::textEdit()
+{
+ QSGView *view = new QSGView;
+ view->setSource(QUrl::fromLocalFile(SRCDIR "/data/test5.qml"));
+
+ QSGFocusScope *item0 = findItem<QSGFocusScope>(view->rootObject(), QLatin1String("item0"));
+ QSGTextEdit *item1 = findItem<QSGTextEdit>(view->rootObject(), QLatin1String("item1"));
+ QSGRectangle *item2 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item2"));
+ QSGTextEdit *item3 = findItem<QSGTextEdit>(view->rootObject(), QLatin1String("item3"));
+ QVERIFY(item0 != 0);
+ QVERIFY(item1 != 0);
+ QVERIFY(item2 != 0);
+ QVERIFY(item3 != 0);
+
+ view->show();
+ qApp->setActiveWindow(view);
+ qApp->processEvents();
+
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(view);
+#endif
+
+ QVERIFY(view->hasFocus());
+ QVERIFY(item0->hasActiveFocus() == true);
+ QVERIFY(item1->hasActiveFocus() == true);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == false);
+
+ QTest::keyClick(view, Qt::Key_Right);
+ QVERIFY(item0->hasActiveFocus() == true);
+ QVERIFY(item1->hasActiveFocus() == true);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == false);
+
+ QTest::keyClick(view, Qt::Key_Right);
+ QTest::keyClick(view, Qt::Key_Right);
+ QTest::keyClick(view, Qt::Key_Right);
+ QTest::keyClick(view, Qt::Key_Right);
+ QTest::keyClick(view, Qt::Key_Right);
+ QVERIFY(item0->hasActiveFocus() == true);
+ QVERIFY(item1->hasActiveFocus() == false);
+ QVERIFY(item2->hasActiveFocus() == true);
+ QVERIFY(item3->hasActiveFocus() == false);
+
+ QTest::keyClick(view, Qt::Key_Down);
+ QVERIFY(item0->hasActiveFocus() == false);
+ QVERIFY(item1->hasActiveFocus() == false);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == true);
+
+ delete view;
+}
+
+void tst_qsgfocusscope::forceFocus()
+{
+ QSGView *view = new QSGView;
+ view->setSource(QUrl::fromLocalFile(SRCDIR "/data/forcefocus.qml"));
+
+ QSGFocusScope *item0 = findItem<QSGFocusScope>(view->rootObject(), QLatin1String("item0"));
+ QSGRectangle *item1 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item1"));
+ QSGRectangle *item2 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item2"));
+ QSGFocusScope *item3 = findItem<QSGFocusScope>(view->rootObject(), QLatin1String("item3"));
+ QSGRectangle *item4 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item4"));
+ QSGRectangle *item5 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item5"));
+ QVERIFY(item0 != 0);
+ QVERIFY(item1 != 0);
+ QVERIFY(item2 != 0);
+ QVERIFY(item3 != 0);
+ QVERIFY(item4 != 0);
+ QVERIFY(item5 != 0);
+
+ view->show();
+ qApp->setActiveWindow(view);
+ qApp->processEvents();
+
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(view);
+#endif
+
+ QVERIFY(view->hasFocus());
+ QVERIFY(item0->hasActiveFocus() == true);
+ QVERIFY(item1->hasActiveFocus() == true);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == false);
+ QVERIFY(item4->hasActiveFocus() == false);
+ QVERIFY(item5->hasActiveFocus() == false);
+
+ QTest::keyClick(view, Qt::Key_4);
+ QVERIFY(item0->hasActiveFocus() == true);
+ QVERIFY(item1->hasActiveFocus() == true);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == false);
+ QVERIFY(item4->hasActiveFocus() == false);
+ QVERIFY(item5->hasActiveFocus() == false);
+
+ QTest::keyClick(view, Qt::Key_5);
+ QVERIFY(item0->hasActiveFocus() == false);
+ QVERIFY(item1->hasActiveFocus() == false);
+ QVERIFY(item2->hasActiveFocus() == false);
+ QVERIFY(item3->hasActiveFocus() == true);
+ QVERIFY(item4->hasActiveFocus() == false);
+ QVERIFY(item5->hasActiveFocus() == true);
+
+ delete view;
+}
+
+void tst_qsgfocusscope::noParentFocus()
+{
+ QSGView *view = new QSGView;
+ view->setSource(QUrl::fromLocalFile(SRCDIR "/data/chain.qml"));
+ QVERIFY(view->rootObject());
+
+ QVERIFY(view->rootObject()->property("focus1") == false);
+ QVERIFY(view->rootObject()->property("focus2") == false);
+ QVERIFY(view->rootObject()->property("focus3") == true);
+ QVERIFY(view->rootObject()->property("focus4") == true);
+ QVERIFY(view->rootObject()->property("focus5") == true);
+
+ delete view;
+}
+
+void tst_qsgfocusscope::signalEmission()
+{
+ QSGView *view = new QSGView;
+ view->setSource(QUrl::fromLocalFile(SRCDIR "/data/signalEmission.qml"));
+
+ QSGRectangle *item1 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item1"));
+ QSGRectangle *item2 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item2"));
+ QSGRectangle *item3 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item3"));
+ QSGRectangle *item4 = findItem<QSGRectangle>(view->rootObject(), QLatin1String("item4"));
+ QVERIFY(item1 != 0);
+ QVERIFY(item2 != 0);
+ QVERIFY(item3 != 0);
+ QVERIFY(item4 != 0);
+
+ view->show();
+ qApp->setActiveWindow(view);
+ qApp->processEvents();
+
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(view);
+#endif
+
+ QVariant blue(QColor("blue"));
+ QVariant red(QColor("red"));
+
+ QVERIFY(view->hasFocus());
+ item1->setFocus(true);
+ QCOMPARE(item1->property("color"), red);
+ QCOMPARE(item2->property("color"), blue);
+ QCOMPARE(item3->property("color"), blue);
+ QCOMPARE(item4->property("color"), blue);
+
+ item2->setFocus(true);
+ QCOMPARE(item1->property("color"), blue);
+ QCOMPARE(item2->property("color"), red);
+ QCOMPARE(item3->property("color"), blue);
+ QCOMPARE(item4->property("color"), blue);
+
+ item3->setFocus(true);
+ QCOMPARE(item1->property("color"), blue);
+ QCOMPARE(item2->property("color"), red);
+ QCOMPARE(item3->property("color"), red);
+ QCOMPARE(item4->property("color"), blue);
+
+ item4->setFocus(true);
+ QCOMPARE(item1->property("color"), blue);
+ QCOMPARE(item2->property("color"), red);
+ QCOMPARE(item3->property("color"), blue);
+ QCOMPARE(item4->property("color"), red);
+
+ item4->setFocus(false);
+ QCOMPARE(item1->property("color"), blue);
+ QCOMPARE(item2->property("color"), red);
+ QCOMPARE(item3->property("color"), blue);
+ QCOMPARE(item4->property("color"), blue);
+
+ delete view;
+}
+
+void tst_qsgfocusscope::qtBug13380()
+{
+ QSGView *view = new QSGView;
+ view->setSource(QUrl::fromLocalFile(SRCDIR "/data/qtBug13380.qml"));
+
+ view->show();
+ QVERIFY(view->rootObject());
+ qApp->setActiveWindow(view);
+ qApp->processEvents();
+
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(view);
+#endif
+
+ QVERIFY(view->hasFocus());
+ QVERIFY(view->rootObject()->property("noFocus").toBool());
+
+ view->rootObject()->setProperty("showRect", true);
+ QVERIFY(view->rootObject()->property("noFocus").toBool());
+
+ delete view;
+}
+
+void tst_qsgfocusscope::forceActiveFocus()
+{
+ QSGView *view = new QSGView;
+ view->setSource(QUrl::fromLocalFile(SRCDIR "/data/forceActiveFocus.qml"));
+
+ QSGItem *rootObject = view->rootObject();
+ QVERIFY(rootObject);
+
+ QSGItem *scope = findItem<QSGItem>(rootObject, QLatin1String("scope"));
+ QSGItem *itemA1 = findItem<QSGItem>(rootObject, QLatin1String("item-a1"));
+ QSGItem *scopeA = findItem<QSGItem>(rootObject, QLatin1String("scope-a"));
+ QSGItem *itemA2 = findItem<QSGItem>(rootObject, QLatin1String("item-a2"));
+ QSGItem *itemB1 = findItem<QSGItem>(rootObject, QLatin1String("item-b1"));
+ QSGItem *scopeB = findItem<QSGItem>(rootObject, QLatin1String("scope-b"));
+ QSGItem *itemB2 = findItem<QSGItem>(rootObject, QLatin1String("item-b2"));
+
+ QVERIFY(scope);
+ QVERIFY(itemA1);
+ QVERIFY(scopeA);
+ QVERIFY(itemA2);
+ QVERIFY(itemB1);
+ QVERIFY(scopeB);
+ QVERIFY(itemB2);
+
+ QSignalSpy rootSpy(rootObject, SIGNAL(activeFocusChanged(bool)));
+ QSignalSpy scopeSpy(scope, SIGNAL(activeFocusChanged(bool)));
+ QSignalSpy scopeASpy(scopeA, SIGNAL(activeFocusChanged(bool)));
+ QSignalSpy scopeBSpy(scopeB, SIGNAL(activeFocusChanged(bool)));
+
+ // First, walk the focus from item-a1 down to item-a2 and back again
+ itemA1->forceActiveFocus();
+ QVERIFY(itemA1->hasActiveFocus());
+ QVERIFY(!rootObject->hasActiveFocus());
+ QCOMPARE(rootSpy.count(), 0);
+ QCOMPARE(scopeSpy.count(), 1);
+
+ scopeA->forceActiveFocus();
+ QVERIFY(!itemA1->hasActiveFocus());
+ QVERIFY(scopeA->hasActiveFocus());
+ QCOMPARE(scopeASpy.count(), 1);
+ QCOMPARE(rootSpy.count(), 0);
+ QCOMPARE(scopeSpy.count(), 1);
+
+ itemA2->forceActiveFocus();
+ QVERIFY(!itemA1->hasActiveFocus());
+ QVERIFY(itemA2->hasActiveFocus());
+ QVERIFY(scopeA->hasActiveFocus());
+ QCOMPARE(scopeASpy.count(), 1);
+ QCOMPARE(rootSpy.count(), 0);
+ QCOMPARE(scopeSpy.count(), 1);
+
+ scopeA->forceActiveFocus();
+ QVERIFY(!itemA1->hasActiveFocus());
+ QVERIFY(itemA2->hasActiveFocus());
+ QVERIFY(scopeA->hasActiveFocus());
+ QCOMPARE(scopeASpy.count(), 1);
+ QCOMPARE(rootSpy.count(), 0);
+ QCOMPARE(scopeSpy.count(), 1);
+
+ itemA1->forceActiveFocus();
+ QVERIFY(itemA1->hasActiveFocus());
+ QVERIFY(!scopeA->hasActiveFocus());
+ QVERIFY(!itemA2->hasActiveFocus());
+ QCOMPARE(scopeASpy.count(), 2);
+ QCOMPARE(rootSpy.count(), 0);
+ QCOMPARE(scopeSpy.count(), 1);
+
+ // Then jump back and forth between branch 'a' and 'b'
+ itemB1->forceActiveFocus();
+ QVERIFY(itemB1->hasActiveFocus());
+ QCOMPARE(rootSpy.count(), 0);
+ QCOMPARE(scopeSpy.count(), 1);
+
+ scopeA->forceActiveFocus();
+ QVERIFY(!itemA1->hasActiveFocus());
+ QVERIFY(!itemB1->hasActiveFocus());
+ QVERIFY(scopeA->hasActiveFocus());
+ QCOMPARE(scopeASpy.count(), 3);
+ QCOMPARE(rootSpy.count(), 0);
+ QCOMPARE(scopeSpy.count(), 1);
+
+ scopeB->forceActiveFocus();
+ QVERIFY(!scopeA->hasActiveFocus());
+ QVERIFY(!itemB1->hasActiveFocus());
+ QVERIFY(scopeB->hasActiveFocus());
+ QCOMPARE(scopeASpy.count(), 4);
+ QCOMPARE(scopeBSpy.count(), 1);
+ QCOMPARE(rootSpy.count(), 0);
+ QCOMPARE(scopeSpy.count(), 1);
+
+ itemA2->forceActiveFocus();
+ QVERIFY(!scopeB->hasActiveFocus());
+ QVERIFY(itemA2->hasActiveFocus());
+ QCOMPARE(scopeASpy.count(), 5);
+ QCOMPARE(scopeBSpy.count(), 2);
+ QCOMPARE(rootSpy.count(), 0);
+ QCOMPARE(scopeSpy.count(), 1);
+
+ itemB2->forceActiveFocus();
+ QVERIFY(!itemA2->hasActiveFocus());
+ QVERIFY(itemB2->hasActiveFocus());
+ QCOMPARE(scopeASpy.count(), 6);
+ QCOMPARE(scopeBSpy.count(), 3);
+ QCOMPARE(rootSpy.count(), 0);
+ QCOMPARE(scopeSpy.count(), 1);
+
+ delete view;
+}
+
+QTEST_MAIN(tst_qsgfocusscope)
+
+#include "tst_qsgfocusscope.moc"
diff --git a/tests/auto/declarative/qsggridview/data/attachedSignals.qml b/tests/auto/declarative/qsggridview/data/attachedSignals.qml
new file mode 100644
index 0000000000..73c10d8caf
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/attachedSignals.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+GridView {
+ id: view
+ width: 240; height: 320
+
+ property variant addedDelegates: []
+ property int removedDelegateCount
+
+ model: testModel
+
+ cellWidth: delegateWidth; cellHeight: delegateHeight
+
+ delegate: Rectangle {
+ width: delegateWidth; height: delegateHeight
+ border.width: 1
+ GridView.onAdd: {
+ var obj = GridView.view.addedDelegates
+ obj.push(model.name)
+ GridView.view.addedDelegates = obj
+ }
+ GridView.onRemove: {
+ view.removedDelegateCount += 1
+ }
+ }
+}
+
diff --git a/tests/auto/declarative/qsggridview/data/displaygrid.qml b/tests/auto/declarative/qsggridview/data/displaygrid.qml
new file mode 100644
index 0000000000..1da4fe50ac
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/displaygrid.qml
@@ -0,0 +1,39 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ width: 80
+ height: 60
+ border.color: "blue"
+ Text {
+ text: index
+ }
+ Text {
+ y: 20
+ id: displayText
+ objectName: "displayText"
+ text: display
+ }
+ color: GridView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ ]
+ GridView {
+ id: grid
+ objectName: "grid"
+ width: 240
+ height: 320
+ cellWidth: 80
+ cellHeight: 60
+ model: testModel
+ delegate: myDelegate
+ }
+}
diff --git a/tests/auto/declarative/qsggridview/data/footer.qml b/tests/auto/declarative/qsggridview/data/footer.qml
new file mode 100644
index 0000000000..b0d1117287
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/footer.qml
@@ -0,0 +1,40 @@
+import QtQuick 2.0
+
+Rectangle {
+ function changeFooter() {
+ grid.footer = footer2
+ }
+ width: 240
+ height: 320
+ color: "#ffffff"
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ width: 80
+ height: 60
+ border.color: "blue"
+ Text {
+ text: index
+ }
+ color: GridView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ GridView {
+ id: grid
+ objectName: "grid"
+ width: 240
+ height: 320
+ cellWidth: 80
+ cellHeight: 60
+ model: testModel
+ delegate: myDelegate
+ footer: Text { objectName: "footer"; text: "Footer"; height: 30 }
+ }
+
+ Component {
+ id: footer2
+ Text { objectName: "footer2"; text: "Footer 2"; height: 20 }
+ }
+}
diff --git a/tests/auto/declarative/qsggridview/data/gridview-enforcerange.qml b/tests/auto/declarative/qsggridview/data/gridview-enforcerange.qml
new file mode 100644
index 0000000000..2bfe7da78e
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/gridview-enforcerange.qml
@@ -0,0 +1,58 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+ Component {
+ id: myDelegate
+ Item {
+ id: wrapper
+ objectName: "wrapper"
+ height: 100
+ width: 100
+ Text {
+ text: index
+ }
+ Text {
+ y: 25
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ y: 50
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ Text {
+ y: 75
+ text: wrapper.y
+ }
+ }
+ }
+
+ Component {
+ id: myHighlight
+ Rectangle {
+ color: "lightsteelblue"
+ }
+ }
+
+ GridView {
+ id: grid
+ objectName: "grid"
+ width: 240
+ height: 320
+ model: testModel
+ delegate: myDelegate
+ highlight: myHighlight
+ flow: (testTopToBottom == true) ? GridView.TopToBottom : GridView.LeftToRight
+ layoutDirection: (testRightToLeft == true) ? Qt.RightToLeft : Qt.LeftToRight
+ preferredHighlightBegin: 100
+ preferredHighlightEnd: 100
+ highlightRangeMode: "StrictlyEnforceRange"
+ focus: true
+ }
+}
diff --git a/tests/auto/declarative/qsggridview/data/gridview-initCurrent.qml b/tests/auto/declarative/qsggridview/data/gridview-initCurrent.qml
new file mode 100644
index 0000000000..c012b4c481
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/gridview-initCurrent.qml
@@ -0,0 +1,52 @@
+import QtQuick 2.0
+
+Rectangle {
+ property int current: grid.currentIndex
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ width: 80
+ height: 60
+ border.color: "blue"
+ Text {
+ text: index
+ }
+ Text {
+ x: 40
+ text: wrapper.x + ", " + wrapper.y
+ }
+ Text {
+ y: 20
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ y: 40
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ color: GridView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ ]
+ GridView {
+ id: grid
+ objectName: "grid"
+ focus: true
+ width: 240
+ height: 320
+ currentIndex: 35
+ cellWidth: 80
+ cellHeight: 60
+ delegate: myDelegate
+ model: testModel
+ }
+}
diff --git a/tests/auto/declarative/qsggridview/data/gridview-noCurrent.qml b/tests/auto/declarative/qsggridview/data/gridview-noCurrent.qml
new file mode 100644
index 0000000000..600716e2d4
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/gridview-noCurrent.qml
@@ -0,0 +1,52 @@
+import QtQuick 2.0
+
+Rectangle {
+ property int current: grid.currentIndex
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ width: 80
+ height: 60
+ border.color: "blue"
+ Text {
+ text: index
+ }
+ Text {
+ x: 40
+ text: wrapper.x + ", " + wrapper.y
+ }
+ Text {
+ y: 20
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ y: 40
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ color: GridView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ ]
+ GridView {
+ id: grid
+ objectName: "grid"
+ focus: true
+ width: 240
+ height: 320
+ currentIndex: -1
+ cellWidth: 80
+ cellHeight: 60
+ delegate: myDelegate
+ model: testModel
+ }
+}
diff --git a/tests/auto/declarative/qsggridview/data/gridview1.qml b/tests/auto/declarative/qsggridview/data/gridview1.qml
new file mode 100644
index 0000000000..816fa5f2d1
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/gridview1.qml
@@ -0,0 +1,65 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ property bool showHeader: false
+ property bool showFooter: false
+ property int added: -1
+ property variant removed
+
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ width: 80
+ height: 60
+ border.color: "blue"
+ Text {
+ text: index
+ }
+ Text {
+ x: 40
+ text: wrapper.x + ", " + wrapper.y
+ }
+ Text {
+ y: 20
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ y: 40
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ color: GridView.isCurrentItem ? "lightsteelblue" : "white"
+ GridView.onAdd: root.added = index
+ GridView.onRemove: root.removed = name
+ }
+ },
+ Component {
+ id: headerFooter
+ Rectangle { width: 30; height: 320; color: "blue" }
+ }
+ ]
+ GridView {
+ id: grid
+ objectName: "grid"
+ width: 240
+ height: 320
+ cellWidth: 80
+ cellHeight: 60
+ flow: (testTopToBottom == false) ? GridView.LeftToRight : GridView.TopToBottom
+ layoutDirection: (testRightToLeft == true) ? Qt.RightToLeft : Qt.LeftToRight
+ model: testModel
+ delegate: myDelegate
+ header: root.showHeader ? headerFooter : null
+ footer: root.showFooter ? headerFooter : null
+ }
+}
diff --git a/tests/auto/declarative/qsggridview/data/gridview2.qml b/tests/auto/declarative/qsggridview/data/gridview2.qml
new file mode 100644
index 0000000000..5fb45a1613
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/gridview2.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+
+GridView {
+ anchors.fill: parent
+ width: 320; height: 200
+ cellWidth: 100; cellHeight: 100; cacheBuffer: 200; focus: true
+ keyNavigationWraps: true; highlightFollowsCurrentItem: false
+
+ model: ListModel {
+ id: appModel
+ ListElement { lColor: "red" }
+ ListElement { lColor: "yellow" }
+ ListElement { lColor: "green" }
+ ListElement { lColor: "blue" }
+ }
+
+ delegate: Item {
+ width: 100; height: 100
+ Rectangle {
+ color: lColor; x: 4; y: 4
+ width: 92; height: 92
+ }
+ }
+
+ highlight: Rectangle { width: 100; height: 100; color: "black" }
+}
diff --git a/tests/auto/declarative/qsggridview/data/gridview3.qml b/tests/auto/declarative/qsggridview/data/gridview3.qml
new file mode 100644
index 0000000000..a8c1c5a0f7
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/gridview3.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+GridView {
+ anchors.fill: parent
+ width: 320; height: 200
+}
diff --git a/tests/auto/declarative/qsggridview/data/header.qml b/tests/auto/declarative/qsggridview/data/header.qml
new file mode 100644
index 0000000000..f725b683a2
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/header.qml
@@ -0,0 +1,40 @@
+import QtQuick 2.0
+
+Rectangle {
+ function changeHeader() {
+ grid.header = header2
+ }
+ width: 240
+ height: 320
+ color: "#ffffff"
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ width: 80
+ height: 60
+ border.color: "blue"
+ Text {
+ text: index
+ }
+ color: GridView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ GridView {
+ id: grid
+ objectName: "grid"
+ width: 240
+ height: 320
+ cellWidth: 80
+ cellHeight: 60
+ model: testModel
+ delegate: myDelegate
+ header: Text { objectName: "header"; text: "Header"; height: 30 }
+ }
+
+ Component {
+ id: header2
+ Text { objectName: "header2"; text: "Header 2"; height: 20 }
+ }
+}
diff --git a/tests/auto/declarative/qsggridview/data/manual-highlight.qml b/tests/auto/declarative/qsggridview/data/manual-highlight.qml
new file mode 100644
index 0000000000..c2f1d20fb1
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/manual-highlight.qml
@@ -0,0 +1,48 @@
+import QtQuick 2.0
+
+Item {
+
+ ListModel {
+ id: model
+ ListElement {
+ name: "Bill Smith"
+ number: "555 3264"
+ }
+ ListElement {
+ name: "John Brown"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Sam Wise"
+ number: "555 0473"
+ }
+ ListElement {
+ name: "Bob Brown"
+ number: "555 5845"
+ }
+ }
+
+ Component {
+ id: highlight
+ Rectangle {
+ objectName: "highlight"
+ width: 80; height: 80
+ color: "lightsteelblue"; radius: 5
+ y: grid.currentItem.y+5
+ x: grid.currentItem.x+5
+ }
+ }
+
+ GridView {
+ id: grid
+ objectName: "grid"
+ anchors.fill: parent
+ model: model
+ delegate: Text { objectName: "wrapper"; text: name; width: 80; height: 80 }
+
+ highlight: highlight
+ highlightFollowsCurrentItem: false
+ focus: true
+ }
+
+}
diff --git a/tests/auto/declarative/qsggridview/data/mirroring.qml b/tests/auto/declarative/qsggridview/data/mirroring.qml
new file mode 100644
index 0000000000..b9aff501c1
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/mirroring.qml
@@ -0,0 +1,43 @@
+// This example demonstrates how item positioning
+// changes in right-to-left layout direction
+
+import QtQuick 2.0
+
+Rectangle {
+ color: "lightgray"
+ width: 340
+ height: 370
+
+ VisualItemModel {
+ id: itemModel
+ objectName: "itemModel"
+ Rectangle {
+ objectName: "item1"
+ height: 110; width: 120; color: "#FFFEF0"
+ Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ Rectangle {
+ objectName: "item2"
+ height: 130; width: 150; color: "#F0FFF7"
+ Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ Rectangle {
+ objectName: "item3"
+ height: 170; width: 190; color: "#F4F0FF"
+ Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ }
+
+ GridView {
+ id: view
+ objectName: "view"
+ cellWidth: 190
+ cellHeight: 170
+ anchors.fill: parent
+ anchors.bottomMargin: 30
+ model: itemModel
+ highlightRangeMode: "StrictlyEnforceRange"
+ flow: GridView.TopToBottom
+ flickDeceleration: 2000
+ }
+}
diff --git a/tests/auto/declarative/qsggridview/data/propertychangestest.qml b/tests/auto/declarative/qsggridview/data/propertychangestest.qml
new file mode 100644
index 0000000000..97efbe78f5
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/propertychangestest.qml
@@ -0,0 +1,69 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 360; height: 120; color: "white"
+ Component {
+ id: delegate
+ Item {
+ id: wrapper
+ width: 180; height: 40;
+ Column {
+ x: 5; y: 5
+ Text { text: '<b>Name:</b> ' + name }
+ Text { text: '<b>Number:</b> ' + number }
+ }
+ }
+ }
+ Component {
+ id: highlightRed
+ Rectangle {
+ color: "red"
+ radius: 10
+ opacity: 0.5
+ }
+ }
+ GridView {
+ cellWidth:180
+ cellHeight:40
+ objectName: "gridView"
+ anchors.fill: parent
+ model: listModel
+ delegate: delegate
+ highlight: highlightRed
+ focus: true
+ keyNavigationWraps: true
+ cacheBuffer: 10
+ flow: GridView.LeftToRight
+ }
+
+ data:[
+ ListModel {
+ id: listModel
+ ListElement {
+ name: "Bill Smith"
+ number: "555 3264"
+ }
+ ListElement {
+ name: "John Brown"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Sam Wise"
+ number: "555 0473"
+ }
+ },
+ ListModel {
+ objectName: "alternateModel"
+ ListElement {
+ name: "Jack"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Mary"
+ number: "555 3264"
+ }
+ }
+ ]
+}
+
+
diff --git a/tests/auto/declarative/qsggridview/data/setindex.qml b/tests/auto/declarative/qsggridview/data/setindex.qml
new file mode 100644
index 0000000000..ef80f3a2fb
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/data/setindex.qml
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 200
+ height: 200
+ Component {
+ id: appDelegate
+
+ Item {
+ id : wrapper
+ function startupFunction() {
+ if (index == 5) view.currentIndex = index;
+ }
+ Component.onCompleted: startupFunction();
+ width: 30; height: 30
+ Text { text: index }
+ }
+ }
+
+ GridView {
+ id: view
+ objectName: "grid"
+ anchors.fill: parent
+ cellWidth: 30; cellHeight: 30
+ model: 35
+ delegate: appDelegate
+ focus: true
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativedom/qdeclarativedom.pro b/tests/auto/declarative/qsggridview/qsggridview.pro
index 8ac69aac67..d76983c24a 100644
--- a/tests/auto/declarative/qdeclarativedom/qdeclarativedom.pro
+++ b/tests/auto/declarative/qsggridview/qsggridview.pro
@@ -2,7 +2,7 @@ load(qttest_p4)
contains(QT_CONFIG,declarative): QT += declarative
macx:CONFIG -= app_bundle
-SOURCES += tst_qdeclarativedom.cpp
+SOURCES += tst_qsggridview.cpp
symbian: {
importFiles.files = data
diff --git a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp
new file mode 100644
index 0000000000..931ae7ee49
--- /dev/null
+++ b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp
@@ -0,0 +1,2171 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtGui/qstringlistmodel.h>
+#include <QtDeclarative/qsgview.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/private/qsgitem_p.h>
+#include <QtDeclarative/private/qlistmodelinterface_p.h>
+#include <QtDeclarative/private/qsggridview_p.h>
+#include <QtDeclarative/private/qsgtext_p.h>
+#include <QtDeclarative/private/qdeclarativelistmodel_p.h>
+#include "../../../shared/util.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_QSGGridView : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QSGGridView();
+
+private slots:
+ void items();
+ void changed();
+ void inserted();
+ void removed();
+ void clear();
+ void moved();
+ void changeFlow();
+ void currentIndex();
+ void noCurrentIndex();
+ void defaultValues();
+ void properties();
+ void propertyChanges();
+ void componentChanges();
+ void modelChanges();
+ void positionViewAtIndex();
+ void positionViewAtIndex_rightToLeft();
+ void mirroring();
+ void snapping();
+ void resetModel();
+ void enforceRange();
+ void enforceRange_rightToLeft();
+ void QTBUG_8456();
+ void manualHighlight();
+ void footer();
+ void header();
+ void indexAt();
+ void onAdd();
+ void onAdd_data();
+ void onRemove();
+ void onRemove_data();
+ void testQtQuick11Attributes();
+ void testQtQuick11Attributes_data();
+
+private:
+ QSGView *createView();
+ template<typename T>
+ T *findItem(QSGItem *parent, const QString &id, int index=-1);
+ template<typename T>
+ QList<T*> findItems(QSGItem *parent, const QString &objectName);
+ void dumpTree(QSGItem *parent, int depth = 0);
+};
+
+class TestModel : public QAbstractListModel
+{
+public:
+ enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
+
+ TestModel(QObject *parent=0) : QAbstractListModel(parent) {
+ QHash<int, QByteArray> roles;
+ roles[Name] = "name";
+ roles[Number] = "number";
+ setRoleNames(roles);
+ }
+
+ int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
+ QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
+ QVariant rv;
+ if (role == Name)
+ rv = list.at(index.row()).first;
+ else if (role == Number)
+ rv = list.at(index.row()).second;
+
+ return rv;
+ }
+
+ int count() const { return rowCount(); }
+ QString name(int index) const { return list.at(index).first; }
+ QString number(int index) const { return list.at(index).second; }
+
+ void addItem(const QString &name, const QString &number) {
+ emit beginInsertRows(QModelIndex(), list.count(), list.count());
+ list.append(QPair<QString,QString>(name, number));
+ emit endInsertRows();
+ }
+
+ void addItems(const QList<QPair<QString, QString> > &items) {
+ emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
+ for (int i=0; i<items.count(); i++)
+ list.append(QPair<QString,QString>(items[i].first, items[i].second));
+ emit endInsertRows();
+ }
+
+ void insertItem(int index, const QString &name, const QString &number) {
+ emit beginInsertRows(QModelIndex(), index, index);
+ list.insert(index, QPair<QString,QString>(name, number));
+ emit endInsertRows();
+ }
+
+ void removeItem(int index) {
+ emit beginRemoveRows(QModelIndex(), index, index);
+ list.removeAt(index);
+ emit endRemoveRows();
+ }
+
+ void removeItems(int index, int count) {
+ emit beginRemoveRows(QModelIndex(), index, index+count-1);
+ while (count--)
+ list.removeAt(index);
+ emit endRemoveRows();
+ }
+
+ void moveItem(int from, int to) {
+ emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
+ list.move(from, to);
+ emit endMoveRows();
+ }
+
+ void modifyItem(int idx, const QString &name, const QString &number) {
+ list[idx] = QPair<QString,QString>(name, number);
+ emit dataChanged(index(idx,0), index(idx,0));
+ }
+
+ void clear() {
+ int count = list.count();
+ emit beginRemoveRows(QModelIndex(), 0, count-1);
+ list.clear();
+ emit endRemoveRows();
+ }
+
+
+private:
+ QList<QPair<QString,QString> > list;
+};
+
+tst_QSGGridView::tst_QSGGridView()
+{
+}
+
+void tst_QSGGridView::items()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ model.addItem("Fred", "12345");
+ model.addItem("John", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Billy", "22345");
+ model.addItem("Sam", "2945");
+ model.addItem("Ben", "04321");
+ model.addItem("Jim", "0780");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QTRY_COMPARE(gridview->count(), model.count());
+ QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+
+ for (int i = 0; i < model.count(); ++i) {
+ QSGText *name = findItem<QSGText>(contentItem, "textName", i);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ // set an empty model and confirm that items are destroyed
+ TestModel model2;
+ ctxt->setContextProperty("testModel", &model2);
+
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ QTRY_VERIFY(itemCount == 0);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::changed()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ model.addItem("Fred", "12345");
+ model.addItem("John", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Billy", "22345");
+ model.addItem("Sam", "2945");
+ model.addItem("Ben", "04321");
+ model.addItem("Jim", "0780");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGFlickable *gridview = findItem<QSGFlickable>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ model.modifyItem(1, "Will", "9876");
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(1));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(1));
+
+ delete canvas;
+}
+
+void tst_QSGGridView::inserted()
+{
+ QSGView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ model.addItem("Fred", "12345");
+ model.addItem("John", "2345");
+ model.addItem("Bob", "54321");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ model.insertItem(1, "Will", "9876");
+
+ QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(1));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(1));
+
+ // Checks that onAdd is called
+ int added = canvas->rootObject()->property("added").toInt();
+ QTRY_COMPARE(added, 1);
+
+ // Confirm items positioned correctly
+ for (int i = 0; i < model.count(); ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ QTRY_COMPARE(item->x(), (i%3)*80.0);
+ QTRY_COMPARE(item->y(), (i/3)*60.0);
+ }
+
+ model.insertItem(0, "Foo", "1111"); // zero index, and current item
+
+ QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+
+ name = findItem<QSGText>(contentItem, "textName", 0);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(0));
+ number = findItem<QSGText>(contentItem, "textNumber", 0);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(0));
+
+ QTRY_COMPARE(gridview->currentIndex(), 1);
+
+ // Confirm items positioned correctly
+ for (int i = 0; i < model.count(); ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ QTRY_VERIFY(item->x() == (i%3)*80);
+ QTRY_VERIFY(item->y() == (i/3)*60);
+ }
+
+ for (int i = model.count(); i < 30; ++i)
+ model.insertItem(i, "Hello", QString::number(i));
+
+ gridview->setContentY(120);
+
+ // Insert item outside visible area
+ model.insertItem(1, "Hello", "1324");
+
+ QTRY_VERIFY(gridview->contentY() == 120);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::removed()
+{
+ QSGView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ for (int i = 0; i < 40; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ model.removeItem(1);
+
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(1));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(1));
+
+ // Checks that onRemove is called
+ QString removed = canvas->rootObject()->property("removed").toString();
+ QTRY_COMPARE(removed, QString("Item1"));
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->x() == (i%3)*80);
+ QTRY_VERIFY(item->y() == (i/3)*60);
+ }
+
+ // Remove first item (which is the current item);
+ model.removeItem(0);
+
+ name = findItem<QSGText>(contentItem, "textName", 0);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(0));
+ number = findItem<QSGText>(contentItem, "textNumber", 0);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(0));
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->x() == (i%3)*80);
+ QTRY_VERIFY(item->y() == (i/3)*60);
+ }
+
+ // Remove items not visible
+ model.removeItem(25);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->x() == (i%3)*80);
+ QTRY_VERIFY(item->y() == (i/3)*60);
+ }
+
+ // Remove items before visible
+ gridview->setContentY(120);
+ gridview->setCurrentIndex(10);
+
+ // Setting currentIndex above shouldn't cause view to scroll
+ QTRY_COMPARE(gridview->contentY(), 120.0);
+
+ model.removeItem(1);
+
+ // Confirm items positioned correctly
+ for (int i = 6; i < 18; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->x() == (i%3)*80);
+ QTRY_VERIFY(item->y() == (i/3)*60);
+ }
+
+ // Remove currentIndex
+ QSGItem *oldCurrent = gridview->currentItem();
+ model.removeItem(9);
+
+ QTRY_COMPARE(gridview->currentIndex(), 9);
+ QTRY_VERIFY(gridview->currentItem() != oldCurrent);
+
+ gridview->setContentY(0);
+ // let transitions settle.
+ QTest::qWait(100);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->x() == (i%3)*80);
+ QTRY_VERIFY(item->y() == (i/3)*60);
+ }
+
+ // remove item outside current view.
+ gridview->setCurrentIndex(32);
+ gridview->setContentY(240);
+
+ model.removeItem(30);
+ QTRY_VERIFY(gridview->currentIndex() == 31);
+
+ // remove current item beyond visible items.
+ gridview->setCurrentIndex(20);
+ gridview->setContentY(0);
+ model.removeItem(20);
+
+ QTRY_COMPARE(gridview->currentIndex(), 20);
+ QTRY_VERIFY(gridview->currentItem() != 0);
+
+ // remove item before current, but visible
+ gridview->setCurrentIndex(8);
+ gridview->setContentY(240);
+ oldCurrent = gridview->currentItem();
+ model.removeItem(6);
+
+ QTRY_COMPARE(gridview->currentIndex(), 7);
+ QTRY_VERIFY(gridview->currentItem() == oldCurrent);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::clear()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QVERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ model.clear();
+
+ QVERIFY(gridview->count() == 0);
+ QVERIFY(gridview->currentItem() == 0);
+ QVERIFY(gridview->contentY() == 0);
+ QVERIFY(gridview->currentIndex() == -1);
+
+ // confirm sanity when adding an item to cleared list
+ model.addItem("New", "1");
+ QVERIFY(gridview->count() == 1);
+ QVERIFY(gridview->currentItem() != 0);
+ QVERIFY(gridview->currentIndex() == 0);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::moved()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ model.moveItem(1, 8);
+
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(1));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(1));
+
+ name = findItem<QSGText>(contentItem, "textName", 8);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(8));
+ number = findItem<QSGText>(contentItem, "textNumber", 8);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(8));
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->x() == (i%3)*80);
+ QTRY_VERIFY(item->y() == (i/3)*60);
+ }
+
+ gridview->setContentY(120);
+
+ // move outside visible area
+ model.moveItem(1, 25);
+
+ // Confirm items positioned correctly and indexes correct
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count()-1;
+ for (int i = 6; i < model.count()-6 && i < itemCount+6; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), qreal((i%3)*80));
+ QTRY_COMPARE(item->y(), qreal((i/3)*60));
+ name = findItem<QSGText>(contentItem, "textName", i);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ number = findItem<QSGText>(contentItem, "textNumber", i);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ // move from outside visible into visible
+ model.moveItem(28, 8);
+
+ // Confirm items positioned correctly and indexes correct
+ for (int i = 6; i < model.count()-6 && i < itemCount+6; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->x() == (i%3)*80);
+ QTRY_VERIFY(item->y() == (i/3)*60);
+ name = findItem<QSGText>(contentItem, "textName", i);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ number = findItem<QSGText>(contentItem, "textNumber", i);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ // ensure content position is stable
+ gridview->setContentY(0);
+ model.moveItem(10, 0);
+ QTRY_VERIFY(gridview->contentY() == 0);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::currentIndex()
+{
+ TestModel model;
+ for (int i = 0; i < 60; i++)
+ model.addItem("Item" + QString::number(i), QString::number(i));
+
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ QString filename(SRCDIR "/data/gridview-initCurrent.qml");
+ canvas->setSource(QUrl::fromLocalFile(filename));
+
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QVERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ // current item should be third item
+ QCOMPARE(gridview->currentIndex(), 35);
+ QCOMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 35));
+ QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
+ QCOMPARE(gridview->contentY(), 400.0);
+
+ gridview->moveCurrentIndexRight();
+ QCOMPARE(gridview->currentIndex(), 36);
+ gridview->moveCurrentIndexDown();
+ QCOMPARE(gridview->currentIndex(), 39);
+ gridview->moveCurrentIndexUp();
+ QCOMPARE(gridview->currentIndex(), 36);
+ gridview->moveCurrentIndexLeft();
+ QCOMPARE(gridview->currentIndex(), 35);
+
+ // no wrap
+ gridview->setCurrentIndex(0);
+ QCOMPARE(gridview->currentIndex(), 0);
+ // confirm that the velocity is updated
+ QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
+
+ gridview->moveCurrentIndexUp();
+ QCOMPARE(gridview->currentIndex(), 0);
+
+ gridview->moveCurrentIndexLeft();
+ QCOMPARE(gridview->currentIndex(), 0);
+
+ gridview->setCurrentIndex(model.count()-1);
+ QCOMPARE(gridview->currentIndex(), model.count()-1);
+
+ gridview->moveCurrentIndexRight();
+ QCOMPARE(gridview->currentIndex(), model.count()-1);
+
+ gridview->moveCurrentIndexDown();
+ QCOMPARE(gridview->currentIndex(), model.count()-1);
+
+ // with wrap
+ gridview->setWrapEnabled(true);
+
+ gridview->setCurrentIndex(0);
+ QCOMPARE(gridview->currentIndex(), 0);
+
+ gridview->moveCurrentIndexLeft();
+ QCOMPARE(gridview->currentIndex(), model.count()-1);
+
+ QTRY_COMPARE(gridview->contentY(), 880.0);
+
+ gridview->moveCurrentIndexRight();
+ QCOMPARE(gridview->currentIndex(), 0);
+
+ QTRY_COMPARE(gridview->contentY(), 0.0);
+
+ // Test keys
+ canvas->show();
+ qApp->setActiveWindow(canvas);
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(canvas);
+#endif
+ QTRY_VERIFY(canvas->hasFocus());
+ qApp->processEvents();
+
+ QTest::keyClick(canvas, Qt::Key_Down);
+ QCOMPARE(gridview->currentIndex(), 3);
+
+ QTest::keyClick(canvas, Qt::Key_Up);
+ QCOMPARE(gridview->currentIndex(), 0);
+
+ gridview->setFlow(QSGGridView::TopToBottom);
+
+ qApp->setActiveWindow(canvas);
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(canvas);
+#endif
+ QTRY_VERIFY(canvas->hasFocus());
+ qApp->processEvents();
+
+ QTest::keyClick(canvas, Qt::Key_Right);
+ QCOMPARE(gridview->currentIndex(), 5);
+
+ QTest::keyClick(canvas, Qt::Key_Left);
+ QCOMPARE(gridview->currentIndex(), 0);
+
+ QTest::keyClick(canvas, Qt::Key_Down);
+ QCOMPARE(gridview->currentIndex(), 1);
+
+ QTest::keyClick(canvas, Qt::Key_Up);
+ QCOMPARE(gridview->currentIndex(), 0);
+
+
+ // turn off auto highlight
+ gridview->setHighlightFollowsCurrentItem(false);
+ QVERIFY(gridview->highlightFollowsCurrentItem() == false);
+ QVERIFY(gridview->highlightItem());
+ qreal hlPosX = gridview->highlightItem()->x();
+ qreal hlPosY = gridview->highlightItem()->y();
+
+ gridview->setCurrentIndex(5);
+ QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
+ QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
+
+ // insert item before currentIndex
+ gridview->setCurrentIndex(28);
+ model.insertItem(0, "Foo", "1111");
+ QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
+
+ // check removing highlight by setting currentIndex to -1;
+ gridview->setCurrentIndex(-1);
+
+ QCOMPARE(gridview->currentIndex(), -1);
+ QVERIFY(!gridview->highlightItem());
+ QVERIFY(!gridview->currentItem());
+
+ gridview->setHighlightFollowsCurrentItem(true);
+
+ gridview->setFlow(QSGGridView::LeftToRight);
+ gridview->setLayoutDirection(Qt::RightToLeft);
+
+ qApp->setActiveWindow(canvas);
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(canvas);
+#endif
+ QTRY_VERIFY(canvas->hasFocus());
+ qApp->processEvents();
+
+ gridview->setCurrentIndex(35);
+
+ QTest::keyClick(canvas, Qt::Key_Right);
+ QCOMPARE(gridview->currentIndex(), 34);
+
+ QTest::keyClick(canvas, Qt::Key_Down);
+ QCOMPARE(gridview->currentIndex(), 37);
+
+ QTest::keyClick(canvas, Qt::Key_Up);
+ QCOMPARE(gridview->currentIndex(), 34);
+
+ QTest::keyClick(canvas, Qt::Key_Left);
+ QCOMPARE(gridview->currentIndex(), 35);
+
+
+ // turn off auto highlight
+ gridview->setHighlightFollowsCurrentItem(false);
+ QVERIFY(gridview->highlightFollowsCurrentItem() == false);
+ QVERIFY(gridview->highlightItem());
+ hlPosX = gridview->highlightItem()->x();
+ hlPosY = gridview->highlightItem()->y();
+
+ gridview->setCurrentIndex(5);
+ QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
+ QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
+
+ // insert item before currentIndex
+ gridview->setCurrentIndex(28);
+ model.insertItem(0, "Foo", "1111");
+ QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
+
+ // check removing highlight by setting currentIndex to -1;
+ gridview->setCurrentIndex(-1);
+
+ QCOMPARE(gridview->currentIndex(), -1);
+ QVERIFY(!gridview->highlightItem());
+ QVERIFY(!gridview->currentItem());
+
+ delete canvas;
+}
+
+void tst_QSGGridView::noCurrentIndex()
+{
+ TestModel model;
+ for (int i = 0; i < 60; i++)
+ model.addItem("Item" + QString::number(i), QString::number(i));
+
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ QString filename(SRCDIR "/data/gridview-noCurrent.qml");
+ canvas->setSource(QUrl::fromLocalFile(filename));
+
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QVERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ // current index should be -1
+ QCOMPARE(gridview->currentIndex(), -1);
+ QVERIFY(!gridview->currentItem());
+ QVERIFY(!gridview->highlightItem());
+ QCOMPARE(gridview->contentY(), 0.0);
+
+ gridview->setCurrentIndex(5);
+ QCOMPARE(gridview->currentIndex(), 5);
+ QVERIFY(gridview->currentItem());
+ QVERIFY(gridview->highlightItem());
+
+ delete canvas;
+}
+
+void tst_QSGGridView::changeFlow()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), QString::number(i));
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // Confirm items positioned correctly and indexes correct
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), qreal((i%3)*80));
+ QTRY_COMPARE(item->y(), qreal((i/3)*60));
+ QSGText *name = findItem<QSGText>(contentItem, "textName", i);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ ctxt->setContextProperty("testTopToBottom", QVariant(true));
+
+ // Confirm items positioned correctly and indexes correct
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), qreal((i/5)*80));
+ QTRY_COMPARE(item->y(), qreal((i%5)*60));
+ QSGText *name = findItem<QSGText>(contentItem, "textName", i);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ ctxt->setContextProperty("testRightToLeft", QVariant(true));
+
+ // Confirm items positioned correctly and indexes correct
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
+ QTRY_COMPARE(item->y(), qreal((i%5)*60));
+ QSGText *name = findItem<QSGText>(contentItem, "textName", i);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+ gridview->setContentX(100);
+ QTRY_COMPARE(gridview->contentX(), 100.);
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+ QTRY_COMPARE(gridview->contentX(), 0.);
+
+ // Confirm items positioned correctly and indexes correct
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
+ QTRY_COMPARE(item->y(), qreal((i/3)*60));
+ QSGText *name = findItem<QSGText>(contentItem, "textName", i);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ delete canvas;
+}
+
+void tst_QSGGridView::defaultValues()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/gridview3.qml"));
+ QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
+
+ QTRY_VERIFY(obj != 0);
+ QTRY_VERIFY(obj->model() == QVariant());
+ QTRY_VERIFY(obj->delegate() == 0);
+ QTRY_COMPARE(obj->currentIndex(), -1);
+ QTRY_VERIFY(obj->currentItem() == 0);
+ QTRY_COMPARE(obj->count(), 0);
+ QTRY_VERIFY(obj->highlight() == 0);
+ QTRY_VERIFY(obj->highlightItem() == 0);
+ QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
+ QTRY_VERIFY(obj->flow() == 0);
+ QTRY_COMPARE(obj->isWrapEnabled(), false);
+ QTRY_COMPARE(obj->cacheBuffer(), 0);
+ QTRY_COMPARE(obj->cellWidth(), 100); //### Should 100 be the default?
+ QTRY_COMPARE(obj->cellHeight(), 100);
+ delete obj;
+}
+
+void tst_QSGGridView::properties()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/gridview2.qml"));
+ QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
+
+ QTRY_VERIFY(obj != 0);
+ QTRY_VERIFY(obj->model() != QVariant());
+ QTRY_VERIFY(obj->delegate() != 0);
+ QTRY_COMPARE(obj->currentIndex(), 0);
+ QTRY_VERIFY(obj->currentItem() != 0);
+ QTRY_COMPARE(obj->count(), 4);
+ QTRY_VERIFY(obj->highlight() != 0);
+ QTRY_VERIFY(obj->highlightItem() != 0);
+ QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
+ QTRY_VERIFY(obj->flow() == 0);
+ QTRY_COMPARE(obj->isWrapEnabled(), true);
+ QTRY_COMPARE(obj->cacheBuffer(), 200);
+ QTRY_COMPARE(obj->cellWidth(), 100);
+ QTRY_COMPARE(obj->cellHeight(), 100);
+ delete obj;
+}
+
+void tst_QSGGridView::propertyChanges()
+{
+ QSGView *canvas = createView();
+ QTRY_VERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
+
+ QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
+ QTRY_VERIFY(gridView);
+
+ QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
+ QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
+ QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
+ QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
+
+ QTRY_COMPARE(gridView->isWrapEnabled(), true);
+ QTRY_COMPARE(gridView->cacheBuffer(), 10);
+ QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
+
+ gridView->setWrapEnabled(false);
+ gridView->setCacheBuffer(3);
+ gridView->setFlow(QSGGridView::TopToBottom);
+
+ QTRY_COMPARE(gridView->isWrapEnabled(), false);
+ QTRY_COMPARE(gridView->cacheBuffer(), 3);
+ QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
+
+ QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
+ QTRY_COMPARE(cacheBufferSpy.count(),1);
+ QTRY_COMPARE(flowSpy.count(),1);
+
+ gridView->setWrapEnabled(false);
+ gridView->setCacheBuffer(3);
+ gridView->setFlow(QSGGridView::TopToBottom);
+
+ QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
+ QTRY_COMPARE(cacheBufferSpy.count(),1);
+ QTRY_COMPARE(flowSpy.count(),1);
+
+ gridView->setFlow(QSGGridView::LeftToRight);
+ QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
+
+ gridView->setWrapEnabled(true);
+ gridView->setCacheBuffer(5);
+ gridView->setLayoutDirection(Qt::RightToLeft);
+
+ QTRY_COMPARE(gridView->isWrapEnabled(), true);
+ QTRY_COMPARE(gridView->cacheBuffer(), 5);
+ QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
+
+ QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
+ QTRY_COMPARE(cacheBufferSpy.count(),2);
+ QTRY_COMPARE(layoutSpy.count(),1);
+ QTRY_COMPARE(flowSpy.count(),2);
+
+ gridView->setWrapEnabled(true);
+ gridView->setCacheBuffer(5);
+ gridView->setLayoutDirection(Qt::RightToLeft);
+
+ QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
+ QTRY_COMPARE(cacheBufferSpy.count(),2);
+ QTRY_COMPARE(layoutSpy.count(),1);
+ QTRY_COMPARE(flowSpy.count(),2);
+
+ gridView->setFlow(QSGGridView::TopToBottom);
+ QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
+ QTRY_COMPARE(flowSpy.count(),3);
+
+ gridView->setFlow(QSGGridView::TopToBottom);
+ QTRY_COMPARE(flowSpy.count(),3);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::componentChanges()
+{
+ QSGView *canvas = createView();
+ QTRY_VERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
+
+ QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
+ QTRY_VERIFY(gridView);
+
+ QDeclarativeComponent component(canvas->engine());
+ component.setData("import QtQuick 1.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
+
+ QDeclarativeComponent delegateComponent(canvas->engine());
+ delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
+
+ QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
+ QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
+ QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
+ QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
+
+ gridView->setHighlight(&component);
+ gridView->setDelegate(&delegateComponent);
+ gridView->setHeader(&component);
+ gridView->setFooter(&component);
+
+ QTRY_COMPARE(gridView->highlight(), &component);
+ QTRY_COMPARE(gridView->delegate(), &delegateComponent);
+ QTRY_COMPARE(gridView->header(), &component);
+ QTRY_COMPARE(gridView->footer(), &component);
+
+ QTRY_COMPARE(highlightSpy.count(),1);
+ QTRY_COMPARE(delegateSpy.count(),1);
+ QTRY_COMPARE(headerSpy.count(),1);
+ QTRY_COMPARE(footerSpy.count(),1);
+
+ gridView->setHighlight(&component);
+ gridView->setDelegate(&delegateComponent);
+ gridView->setHeader(&component);
+ gridView->setFooter(&component);
+
+ QTRY_COMPARE(highlightSpy.count(),1);
+ QTRY_COMPARE(delegateSpy.count(),1);
+ QTRY_COMPARE(headerSpy.count(),1);
+ QTRY_COMPARE(footerSpy.count(),1);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::modelChanges()
+{
+ QSGView *canvas = createView();
+ QTRY_VERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
+
+ QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
+ QTRY_VERIFY(gridView);
+
+ QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
+ QTRY_VERIFY(alternateModel);
+ QVariant modelVariant = QVariant::fromValue(alternateModel);
+ QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
+
+ gridView->setModel(modelVariant);
+ QTRY_COMPARE(gridView->model(), modelVariant);
+ QTRY_COMPARE(modelSpy.count(),1);
+
+ gridView->setModel(modelVariant);
+ QTRY_COMPARE(modelSpy.count(),1);
+
+ gridView->setModel(QVariant());
+ QTRY_COMPARE(modelSpy.count(),2);
+ delete canvas;
+}
+
+void tst_QSGGridView::positionViewAtIndex()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 40; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), (i%3)*80.);
+ QTRY_COMPARE(item->y(), (i/3)*60.);
+ }
+
+ // Position on a currently visible item
+ gridview->positionViewAtIndex(4, QSGGridView::Beginning);
+ QTRY_COMPARE(gridview->indexAt(120, 90), 4);
+ QTRY_COMPARE(gridview->contentY(), 60.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), (i%3)*80.);
+ QTRY_COMPARE(item->y(), (i/3)*60.);
+ }
+
+ // Position on an item beyond the visible items
+ gridview->positionViewAtIndex(21, QSGGridView::Beginning);
+ QTRY_COMPARE(gridview->indexAt(40, 450), 21);
+ QTRY_COMPARE(gridview->contentY(), 420.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), (i%3)*80.);
+ QTRY_COMPARE(item->y(), (i/3)*60.);
+ }
+
+ // Position on an item that would leave empty space if positioned at the top
+ gridview->positionViewAtIndex(31, QSGGridView::Beginning);
+ QTRY_COMPARE(gridview->indexAt(120, 630), 31);
+ QTRY_COMPARE(gridview->contentY(), 520.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), (i%3)*80.);
+ QTRY_COMPARE(item->y(), (i/3)*60.);
+ }
+
+ // Position at the beginning again
+ gridview->positionViewAtIndex(0, QSGGridView::Beginning);
+ QTRY_COMPARE(gridview->indexAt(0, 0), 0);
+ QTRY_COMPARE(gridview->indexAt(40, 30), 0);
+ QTRY_COMPARE(gridview->indexAt(80, 60), 4);
+ QTRY_COMPARE(gridview->contentY(), 0.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), (i%3)*80.);
+ QTRY_COMPARE(item->y(), (i/3)*60.);
+ }
+
+ // Position at End
+ gridview->positionViewAtIndex(30, QSGGridView::End);
+ QTRY_COMPARE(gridview->contentY(), 340.);
+
+ // Position in Center
+ gridview->positionViewAtIndex(15, QSGGridView::Center);
+ QTRY_COMPARE(gridview->contentY(), 170.);
+
+ // Ensure at least partially visible
+ gridview->positionViewAtIndex(15, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentY(), 170.);
+
+ gridview->setContentY(302);
+ gridview->positionViewAtIndex(15, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentY(), 302.);
+
+ gridview->setContentY(360);
+ gridview->positionViewAtIndex(15, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentY(), 300.);
+
+ gridview->setContentY(60);
+ gridview->positionViewAtIndex(20, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentY(), 60.);
+
+ gridview->setContentY(20);
+ gridview->positionViewAtIndex(20, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentY(), 100.);
+
+ // Ensure completely visible
+ gridview->setContentY(120);
+ gridview->positionViewAtIndex(20, QSGGridView::Contain);
+ QTRY_COMPARE(gridview->contentY(), 120.);
+
+ gridview->setContentY(302);
+ gridview->positionViewAtIndex(15, QSGGridView::Contain);
+ QTRY_COMPARE(gridview->contentY(), 300.);
+
+ gridview->setContentY(60);
+ gridview->positionViewAtIndex(20, QSGGridView::Contain);
+ QTRY_COMPARE(gridview->contentY(), 100.);
+
+ // Test for Top To Bottom layout
+ ctxt->setContextProperty("testTopToBottom", QVariant(true));
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), (i/5)*80.);
+ QTRY_COMPARE(item->y(), (i%5)*60.);
+ }
+
+ // Position at End
+ gridview->positionViewAtIndex(30, QSGGridView::End);
+ QTRY_COMPARE(gridview->contentX(), 320.);
+ QTRY_COMPARE(gridview->contentY(), 0.);
+
+ // Position in Center
+ gridview->positionViewAtIndex(15, QSGGridView::Center);
+ QTRY_COMPARE(gridview->contentX(), 160.);
+
+ // Ensure at least partially visible
+ gridview->positionViewAtIndex(15, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentX(), 160.);
+
+ gridview->setContentX(170);
+ gridview->positionViewAtIndex(25, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentX(), 170.);
+
+ gridview->positionViewAtIndex(30, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentX(), 320.);
+
+ gridview->setContentX(170);
+ gridview->positionViewAtIndex(25, QSGGridView::Contain);
+ QTRY_COMPARE(gridview->contentX(), 240.);
+
+ // positionViewAtBeginning
+ gridview->positionViewAtBeginning();
+ QTRY_COMPARE(gridview->contentX(), 0.);
+
+ gridview->setContentX(80);
+ canvas->rootObject()->setProperty("showHeader", true);
+ gridview->positionViewAtBeginning();
+ QTRY_COMPARE(gridview->contentX(), -30.);
+
+ // positionViewAtEnd
+ gridview->positionViewAtEnd();
+ QTRY_COMPARE(gridview->contentX(), 430.);
+
+ gridview->setContentX(80);
+ canvas->rootObject()->setProperty("showFooter", true);
+ gridview->positionViewAtEnd();
+ QTRY_COMPARE(gridview->contentX(), 460.);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::snapping()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 40; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ gridview->setHeight(220);
+ QCOMPARE(gridview->height(), 220.);
+
+ gridview->positionViewAtIndex(12, QSGGridView::Visible);
+ QCOMPARE(gridview->contentY(), 80.);
+
+ gridview->setContentY(0);
+ QCOMPARE(gridview->contentY(), 0.);
+
+ gridview->setSnapMode(QSGGridView::SnapToRow);
+ QCOMPARE(gridview->snapMode(), QSGGridView::SnapToRow);
+
+ gridview->positionViewAtIndex(12, QSGGridView::Visible);
+ QCOMPARE(gridview->contentY(), 60.);
+
+ gridview->positionViewAtIndex(15, QSGGridView::End);
+ QCOMPARE(gridview->contentY(), 120.);
+
+ delete canvas;
+
+}
+
+void tst_QSGGridView::mirroring()
+{
+ QSGView *canvasA = createView();
+ canvasA->setSource(QUrl::fromLocalFile(SRCDIR "/data/mirroring.qml"));
+ QSGGridView *gridviewA = findItem<QSGGridView>(canvasA->rootObject(), "view");
+ QTRY_VERIFY(gridviewA != 0);
+
+ QSGView *canvasB = createView();
+ canvasB->setSource(QUrl::fromLocalFile(SRCDIR "/data/mirroring.qml"));
+ QSGGridView *gridviewB = findItem<QSGGridView>(canvasB->rootObject(), "view");
+ QTRY_VERIFY(gridviewA != 0);
+ qApp->processEvents();
+
+ QList<QString> objectNames;
+ objectNames << "item1" << "item2"; // << "item3"
+
+ gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
+ gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
+ QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
+
+ // LTR != RTL
+ foreach(const QString objectName, objectNames)
+ QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
+
+ gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
+ gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
+
+ // LTR == LTR
+ foreach(const QString objectName, objectNames)
+ QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
+
+ QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
+ QSGItemPrivate::get(gridviewB)->setLayoutMirror(true);
+ QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
+
+ // LTR != LTR+mirror
+ foreach(const QString objectName, objectNames)
+ QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
+
+ gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
+
+ // RTL == LTR+mirror
+ foreach(const QString objectName, objectNames)
+ QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
+
+ gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
+
+ // RTL != RTL+mirror
+ foreach(const QString objectName, objectNames)
+ QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
+
+ gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
+
+ // LTR == RTL+mirror
+ foreach(const QString objectName, objectNames)
+ QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
+
+ delete canvasA;
+ delete canvasB;
+}
+
+void tst_QSGGridView::positionViewAtIndex_rightToLeft()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 40; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testTopToBottom", QVariant(true));
+ ctxt->setContextProperty("testRightToLeft", QVariant(true));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
+ QTRY_COMPARE(item->y(), qreal((i%5)*60));
+ }
+
+ // Position on a currently visible item
+ gridview->positionViewAtIndex(6, QSGGridView::Beginning);
+ QTRY_COMPARE(gridview->contentX(), -320.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
+ QTRY_COMPARE(item->y(), qreal((i%5)*60));
+ }
+
+ // Position on an item beyond the visible items
+ gridview->positionViewAtIndex(21, QSGGridView::Beginning);
+ QTRY_COMPARE(gridview->contentX(), -560.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
+ QTRY_COMPARE(item->y(), qreal((i%5)*60));
+ }
+
+ // Position on an item that would leave empty space if positioned at the top
+ gridview->positionViewAtIndex(31, QSGGridView::Beginning);
+ QTRY_COMPARE(gridview->contentX(), -639.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
+ QTRY_COMPARE(item->y(), qreal((i%5)*60));
+ }
+
+ // Position at the beginning again
+ gridview->positionViewAtIndex(0, QSGGridView::Beginning);
+ QTRY_COMPARE(gridview->contentX(), -240.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
+ QTRY_COMPARE(item->y(), qreal((i%5)*60));
+ }
+
+ // Position at End
+ gridview->positionViewAtIndex(30, QSGGridView::End);
+ QTRY_COMPARE(gridview->contentX(), -560.);
+
+ // Position in Center
+ gridview->positionViewAtIndex(15, QSGGridView::Center);
+ QTRY_COMPARE(gridview->contentX(), -400.);
+
+ // Ensure at least partially visible
+ gridview->positionViewAtIndex(15, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentX(), -400.);
+
+ gridview->setContentX(-555.);
+ gridview->positionViewAtIndex(15, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentX(), -555.);
+
+ gridview->setContentX(-239);
+ gridview->positionViewAtIndex(15, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentX(), -320.);
+
+ gridview->setContentX(-239);
+ gridview->positionViewAtIndex(20, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentX(), -400.);
+
+ gridview->setContentX(-640);
+ gridview->positionViewAtIndex(20, QSGGridView::Visible);
+ QTRY_COMPARE(gridview->contentX(), -560.);
+
+ // Ensure completely visible
+ gridview->setContentX(-400);
+ gridview->positionViewAtIndex(20, QSGGridView::Contain);
+ QTRY_COMPARE(gridview->contentX(), -400.);
+
+ gridview->setContentX(-315);
+ gridview->positionViewAtIndex(15, QSGGridView::Contain);
+ QTRY_COMPARE(gridview->contentX(), -320.);
+
+ gridview->setContentX(-640);
+ gridview->positionViewAtIndex(20, QSGGridView::Contain);
+ QTRY_COMPARE(gridview->contentX(), -560.);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::resetModel()
+{
+ QSGView *canvas = createView();
+
+ QStringList strings;
+ strings << "one" << "two" << "three";
+ QStringListModel model(strings);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaygrid.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QTRY_COMPARE(gridview->count(), model.rowCount());
+
+ for (int i = 0; i < model.rowCount(); ++i) {
+ QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
+ QTRY_VERIFY(display != 0);
+ QTRY_COMPARE(display->text(), strings.at(i));
+ }
+
+ strings.clear();
+ strings << "four" << "five" << "six" << "seven";
+ model.setStringList(strings);
+
+ QTRY_COMPARE(gridview->count(), model.rowCount());
+
+ for (int i = 0; i < model.rowCount(); ++i) {
+ QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
+ QTRY_VERIFY(display != 0);
+ QTRY_COMPARE(display->text(), strings.at(i));
+ }
+
+ delete canvas;
+}
+
+void tst_QSGGridView::enforceRange()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview-enforcerange.qml"));
+ qApp->processEvents();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
+ QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
+ QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // view should be positioned at the top of the range.
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(gridview->contentY(), -100.0);
+
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(0));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(0));
+
+ // Check currentIndex is updated when contentItem moves
+ gridview->setContentY(0);
+ QTRY_COMPARE(gridview->currentIndex(), 2);
+
+ gridview->setCurrentIndex(5);
+ QTRY_COMPARE(gridview->contentY(), 100.);
+
+ TestModel model2;
+ for (int i = 0; i < 5; i++)
+ model2.addItem("Item" + QString::number(i), "");
+
+ ctxt->setContextProperty("testModel", &model2);
+ QCOMPARE(gridview->count(), 5);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::enforceRange_rightToLeft()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(true));
+ ctxt->setContextProperty("testTopToBottom", QVariant(true));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview-enforcerange.qml"));
+ qApp->processEvents();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
+ QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
+ QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // view should be positioned at the top of the range.
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(gridview->contentX(), -100.);
+ QTRY_COMPARE(gridview->contentY(), 0.0);
+
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(0));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(0));
+
+ // Check currentIndex is updated when contentItem moves
+ gridview->setContentX(-200);
+ QTRY_COMPARE(gridview->currentIndex(), 3);
+
+ gridview->setCurrentIndex(7);
+ QTRY_COMPARE(gridview->contentX(), -300.);
+ QTRY_COMPARE(gridview->contentY(), 0.0);
+
+ TestModel model2;
+ for (int i = 0; i < 5; i++)
+ model2.addItem("Item" + QString::number(i), "");
+
+ ctxt->setContextProperty("testModel", &model2);
+ QCOMPARE(gridview->count(), 5);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::QTBUG_8456()
+{
+ QSGView *canvas = createView();
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/setindex.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QTRY_COMPARE(gridview->currentIndex(), 0);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::manualHighlight()
+{
+ QSGView *canvas = createView();
+
+ QString filename(SRCDIR "/data/manual-highlight.qml");
+ canvas->setSource(QUrl::fromLocalFile(filename));
+
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QTRY_COMPARE(gridview->currentIndex(), 0);
+ QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
+ QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
+ QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
+
+ gridview->setCurrentIndex(2);
+
+ QTRY_COMPARE(gridview->currentIndex(), 2);
+ QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
+ QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
+ QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
+
+ gridview->positionViewAtIndex(8, QSGGridView::Contain);
+
+ QTRY_COMPARE(gridview->currentIndex(), 2);
+ QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
+ QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
+ QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
+
+ gridview->setFlow(QSGGridView::TopToBottom);
+ QTRY_COMPARE(gridview->flow(), QSGGridView::TopToBottom);
+
+ gridview->setCurrentIndex(0);
+ QTRY_COMPARE(gridview->currentIndex(), 0);
+ QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
+ QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
+ QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
+
+ delete canvas;
+}
+
+void tst_QSGGridView::footer()
+{
+ QSGView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ for (int i = 0; i < 7; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/footer.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QSGText *footer = findItem<QSGText>(contentItem, "footer");
+ QVERIFY(footer);
+
+ QCOMPARE(footer->y(), 180.0);
+ QCOMPARE(footer->height(), 30.0);
+
+ model.removeItem(2);
+ QTRY_COMPARE(footer->y(), 120.0);
+
+ model.clear();
+ QTRY_COMPARE(footer->y(), 0.0);
+
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
+
+ footer = findItem<QSGText>(contentItem, "footer");
+ QVERIFY(!footer);
+ footer = findItem<QSGText>(contentItem, "footer2");
+ QVERIFY(footer);
+
+ QCOMPARE(footer->y(), 600.0);
+ QCOMPARE(footer->height(), 20.0);
+ QCOMPARE(gridview->contentY(), 0.0);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::header()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QSGText *header = findItem<QSGText>(contentItem, "header");
+ QVERIFY(header);
+
+ QCOMPARE(header->y(), 0.0);
+ QCOMPARE(header->height(), 30.0);
+ QCOMPARE(gridview->contentY(), 0.0);
+
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
+ QVERIFY(item);
+ QCOMPARE(item->y(), 30.0);
+
+ model.clear();
+ QTRY_COMPARE(header->y(), 0.0);
+
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
+
+ header = findItem<QSGText>(contentItem, "header");
+ QVERIFY(!header);
+ header = findItem<QSGText>(contentItem, "header2");
+ QVERIFY(header);
+
+ QCOMPARE(header->y(), 10.0);
+ QCOMPARE(header->height(), 20.0);
+ QCOMPARE(gridview->contentY(), 10.0);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::indexAt()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ model.addItem("Fred", "12345");
+ model.addItem("John", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Billy", "22345");
+ model.addItem("Sam", "2945");
+ model.addItem("Ben", "04321");
+ model.addItem("Jim", "0780");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QTRY_COMPARE(gridview->count(), model.count());
+
+ QCOMPARE(gridview->indexAt(0, 0), 0);
+ QCOMPARE(gridview->indexAt(79, 59), 0);
+ QCOMPARE(gridview->indexAt(80, 0), 1);
+ QCOMPARE(gridview->indexAt(0, 60), 3);
+ QCOMPARE(gridview->indexAt(240, 0), -1);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::onAdd()
+{
+ QFETCH(int, initialItemCount);
+ QFETCH(int, itemsToAdd);
+
+ const int delegateWidth = 50;
+ const int delegateHeight = 100;
+ TestModel model;
+ QSGView *canvas = createView();
+ canvas->setFixedSize(5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
+
+ // these initial items should not trigger GridView.onAdd
+ for (int i=0; i<initialItemCount; i++)
+ model.addItem("dummy value", "dummy value");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("delegateWidth", delegateWidth);
+ ctxt->setContextProperty("delegateHeight", delegateHeight);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
+
+ QObject *object = canvas->rootObject();
+ object->setProperty("width", canvas->width());
+ object->setProperty("height", canvas->height());
+ qApp->processEvents();
+
+ QList<QPair<QString, QString> > items;
+ for (int i=0; i<itemsToAdd; i++)
+ items << qMakePair(QString("value %1").arg(i), QString::number(i));
+ model.addItems(items);
+
+ qApp->processEvents();
+
+ QVariantList result = object->property("addedDelegates").toList();
+ QCOMPARE(result.count(), items.count());
+ for (int i=0; i<items.count(); i++)
+ QCOMPARE(result[i].toString(), items[i].first);
+
+ delete canvas;
+}
+
+void tst_QSGGridView::onAdd_data()
+{
+ QTest::addColumn<int>("initialItemCount");
+ QTest::addColumn<int>("itemsToAdd");
+
+ QTest::newRow("0, add 1") << 0 << 1;
+ QTest::newRow("0, add 2") << 0 << 2;
+ QTest::newRow("0, add 10") << 0 << 10;
+
+ QTest::newRow("1, add 1") << 1 << 1;
+ QTest::newRow("1, add 2") << 1 << 2;
+ QTest::newRow("1, add 10") << 1 << 10;
+
+ QTest::newRow("5, add 1") << 5 << 1;
+ QTest::newRow("5, add 2") << 5 << 2;
+ QTest::newRow("5, add 10") << 5 << 10;
+}
+
+void tst_QSGGridView::onRemove()
+{
+ QFETCH(int, initialItemCount);
+ QFETCH(int, indexToRemove);
+ QFETCH(int, removeCount);
+
+ const int delegateWidth = 50;
+ const int delegateHeight = 100;
+ TestModel model;
+ for (int i=0; i<initialItemCount; i++)
+ model.addItem(QString("value %1").arg(i), "dummy value");
+
+ QSGView *canvas = createView();
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("delegateWidth", delegateWidth);
+ ctxt->setContextProperty("delegateHeight", delegateHeight);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
+ QObject *object = canvas->rootObject();
+
+ qApp->processEvents();
+
+ model.removeItems(indexToRemove, removeCount);
+ qApp->processEvents();
+ QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
+
+ delete canvas;
+}
+
+void tst_QSGGridView::onRemove_data()
+{
+ QTest::addColumn<int>("initialItemCount");
+ QTest::addColumn<int>("indexToRemove");
+ QTest::addColumn<int>("removeCount");
+
+ QTest::newRow("remove first") << 1 << 0 << 1;
+ QTest::newRow("two items, remove first") << 2 << 0 << 1;
+ QTest::newRow("two items, remove last") << 2 << 1 << 1;
+ QTest::newRow("two items, remove all") << 2 << 0 << 2;
+
+ QTest::newRow("four items, remove first") << 4 << 0 << 1;
+ QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
+ QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
+ QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
+ QTest::newRow("four items, remove last") << 4 << 3 << 1;
+ QTest::newRow("four items, remove all") << 4 << 0 << 4;
+
+ QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
+ QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
+ QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
+}
+
+void tst_QSGGridView::testQtQuick11Attributes()
+{
+ QFETCH(QString, code);
+ QFETCH(QString, warning);
+ QFETCH(QString, error);
+
+ QDeclarativeEngine engine;
+ QObject *obj;
+
+ QDeclarativeComponent valid(&engine);
+ valid.setData("import QtQuick 1.1; GridView { " + code.toUtf8() + " }", QUrl(""));
+ obj = valid.create();
+ QVERIFY(obj);
+ QVERIFY(valid.errorString().isEmpty());
+ delete obj;
+
+ QDeclarativeComponent invalid(&engine);
+ invalid.setData("import QtQuick 1.0; GridView { " + code.toUtf8() + " }", QUrl(""));
+ QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
+ obj = invalid.create();
+ QCOMPARE(invalid.errorString(), error);
+ delete obj;
+}
+
+void tst_QSGGridView::testQtQuick11Attributes_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("positionViewAtBeginning") << "Component.onCompleted: positionViewAtBeginning()"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtBeginning"
+ << "";
+
+ QTest::newRow("positionViewAtEnd") << "Component.onCompleted: positionViewAtEnd()"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtEnd"
+ << "";
+}
+
+QSGView *tst_QSGGridView::createView()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ return canvas;
+}
+
+/*
+ Find an item with the specified objectName. If index is supplied then the
+ item must also evaluate the {index} expression equal to index
+*/
+template<typename T>
+T *tst_QSGGridView::findItem(QSGItem *parent, const QString &objectName, int index)
+{
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->childItems().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ if (index != -1) {
+ QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
+ if (context) {
+ if (context->contextProperty("index").toInt() == index) {
+ return static_cast<T*>(item);
+ }
+ }
+ } else {
+ return static_cast<T*>(item);
+ }
+ }
+ item = findItem<T>(item, objectName, index);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+}
+
+template<typename T>
+QList<T*> tst_QSGGridView::findItems(QSGItem *parent, const QString &objectName)
+{
+ QList<T*> items;
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->childItems().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ items.append(static_cast<T*>(item));
+ //qDebug() << " found:" << item;
+ }
+ items += findItems<T>(item, objectName);
+ }
+
+ return items;
+}
+
+void tst_QSGGridView::dumpTree(QSGItem *parent, int depth)
+{
+ static QString padding(" ");
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
+ qDebug() << padding.left(depth*2) << item << (context ? context->contextProperty("index").toInt() : -1);
+ dumpTree(item, depth+1);
+ }
+}
+
+
+QTEST_MAIN(tst_QSGGridView)
+
+#include "tst_qsggridview.moc"
diff --git a/tests/auto/declarative/qsgimage/data/aspectratio.qml b/tests/auto/declarative/qsgimage/data/aspectratio.qml
new file mode 100644
index 0000000000..b26f0e1f04
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/aspectratio.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+Image {
+ source: "heart.png"
+ fillMode: Image.PreserveAspectFit;
+}
diff --git a/tests/auto/declarative/qsgimage/data/big.jpeg b/tests/auto/declarative/qsgimage/data/big.jpeg
new file mode 100644
index 0000000000..bed7bd65c3
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/big.jpeg
Binary files differ
diff --git a/tests/auto/declarative/qsgimage/data/big256.png b/tests/auto/declarative/qsgimage/data/big256.png
new file mode 100644
index 0000000000..1dc1596d03
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/big256.png
Binary files differ
diff --git a/tests/auto/declarative/qsgimage/data/colors.png b/tests/auto/declarative/qsgimage/data/colors.png
new file mode 100644
index 0000000000..dfb62f3d64
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/colors.png
Binary files differ
diff --git a/tests/auto/declarative/qsgimage/data/colors1.png b/tests/auto/declarative/qsgimage/data/colors1.png
new file mode 100644
index 0000000000..dfb62f3d64
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/colors1.png
Binary files differ
diff --git a/tests/auto/declarative/qsgimage/data/green.png b/tests/auto/declarative/qsgimage/data/green.png
new file mode 100644
index 0000000000..0a2e153ba1
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/green.png
Binary files differ
diff --git a/tests/auto/declarative/qsgimage/data/heart-win32.png b/tests/auto/declarative/qsgimage/data/heart-win32.png
new file mode 100644
index 0000000000..351da13772
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/heart-win32.png
Binary files differ
diff --git a/tests/auto/declarative/qsgimage/data/heart.png b/tests/auto/declarative/qsgimage/data/heart.png
new file mode 100644
index 0000000000..abe97fee4b
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/heart.png
Binary files differ
diff --git a/tests/auto/declarative/qsgimage/data/heart.svg b/tests/auto/declarative/qsgimage/data/heart.svg
new file mode 100644
index 0000000000..8c982cd93c
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/heart.svg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) --><svg viewBox="100 200 550 500" height="841.88976pt" id="svg1" inkscape:version="0.40+cvs" sodipodi:docbase="C:\Documents and Settings\Jon Phillips\My Documents\projects\clipart-project\submissions" sodipodi:docname="heart-left-highlight.svg" sodipodi:version="0.32" width="595.27559pt" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg">
+<metadata>
+<rdf:RDF xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<cc:Work rdf:about="">
+<dc:title>Heart Left-Highlight</dc:title>
+<dc:description>This is a normal valentines day heart.</dc:description>
+<dc:subject>
+<rdf:Bag>
+<rdf:li>holiday</rdf:li>
+<rdf:li>valentines</rdf:li>
+<rdf:li></rdf:li>
+<rdf:li>valentine</rdf:li>
+<rdf:li>hash(0x8a091c0)</rdf:li>
+<rdf:li>hash(0x8a0916c)</rdf:li>
+<rdf:li>signs_and_symbols</rdf:li>
+<rdf:li>hash(0x8a091f0)</rdf:li>
+<rdf:li>day</rdf:li>
+</rdf:Bag>
+</dc:subject>
+<dc:publisher>
+<cc:Agent rdf:about="http://www.openclipart.org">
+<dc:title>Jon Phillips</dc:title>
+</cc:Agent>
+</dc:publisher>
+<dc:creator>
+<cc:Agent>
+<dc:title>Jon Phillips</dc:title>
+</cc:Agent>
+</dc:creator>
+<dc:rights>
+<cc:Agent>
+<dc:title>Jon Phillips</dc:title>
+</cc:Agent>
+</dc:rights>
+<dc:date></dc:date>
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<cc:license rdf:resource="http://web.resource.org/cc/PublicDomain"/>
+<dc:language>en</dc:language>
+</cc:Work>
+<cc:License rdf:about="http://web.resource.org/cc/PublicDomain">
+<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
+<cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/>
+<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
+</cc:License>
+</rdf:RDF>
+</metadata>
+<defs id="defs3"/>
+<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" id="base" inkscape:current-layer="layer1" inkscape:cx="549.40674" inkscape:cy="596.00159" inkscape:document-units="px" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-height="615" inkscape:window-width="866" inkscape:window-x="88" inkscape:window-y="116" inkscape:zoom="0.35000000" pagecolor="#ffffff" showguides="true"/>
+<g id="layer1" inkscape:groupmode="layer" inkscape:label="Layer 1">
+<path d="M 263.41570,235.14588 C 197.17570,235.14588 143.41575,288.90587 143.41575,355.14588 C 143.41575,489.90139 279.34890,525.23318 371.97820,658.45392 C 459.55244,526.05056 600.54070,485.59932 600.54070,355.14588 C 600.54070,288.90588 546.78080,235.14587 480.54070,235.14588 C 432.49280,235.14588 391.13910,263.51631 371.97820,304.33338 C 352.81740,263.51630 311.46370,235.14587 263.41570,235.14588 z " id="path7" sodipodi:nodetypes="ccccccc" style="fill:#e60000;fill-opacity:1.0000000;stroke:#000000;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/>
+<path d="M 265.00000,253.59375 C 207.04033,253.59375 160.00000,300.63407 160.00000,358.59375 C 160.00000,476.50415 278.91857,507.43251 359.96875,624.00000 C 366.52868,614.08205 220.00000,478.47309 220.00000,378.59375 C 220.00000,320.63407 267.04033,273.59375 325.00000,273.59375 C 325.50453,273.59375 325.99718,273.64912 326.50000,273.65625 C 309.22436,261.07286 288.00557,253.59374 265.00000,253.59375 z " id="path220" sodipodi:nodetypes="ccccccc" style="fill:#e6e6e6;fill-opacity:0.64556962;stroke:none;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/>
+</g>
+</svg>
diff --git a/tests/auto/declarative/qsgimage/data/heart200-win32.png b/tests/auto/declarative/qsgimage/data/heart200-win32.png
new file mode 100644
index 0000000000..4976ff98ba
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/heart200-win32.png
Binary files differ
diff --git a/tests/auto/declarative/qsgimage/data/heart200.png b/tests/auto/declarative/qsgimage/data/heart200.png
new file mode 100644
index 0000000000..7fbb13c5bb
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/heart200.png
Binary files differ
diff --git a/tests/auto/declarative/qsgimage/data/qtbug_16389.qml b/tests/auto/declarative/qsgimage/data/qtbug_16389.qml
new file mode 100644
index 0000000000..7b8adecb11
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/qtbug_16389.qml
@@ -0,0 +1,30 @@
+import QtQuick 2.0
+Rectangle {
+ width: 400
+ height: 400
+
+ Item {
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.bottom: blueHandle.top
+ anchors.right: blueHandle.left
+
+ Image {
+ id: iconImage
+ objectName: "iconImage"
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ source: "heart200.png"
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+ }
+ }
+
+ Rectangle {
+ id: blueHandle
+ objectName: "blueHandle"
+ color: "blue"
+ width: 25
+ height: 25
+ }
+}
diff --git a/tests/auto/declarative/qsgimage/data/rect.png b/tests/auto/declarative/qsgimage/data/rect.png
new file mode 100644
index 0000000000..d564a2d5a5
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/rect.png
Binary files differ
diff --git a/tests/auto/declarative/qsgimage/data/tiling.qml b/tests/auto/declarative/qsgimage/data/tiling.qml
new file mode 100644
index 0000000000..986b7708a2
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/data/tiling.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 800; height: 600
+
+ Image {
+ objectName: "vTiling"; height: 550; width: 200
+ source: "green.png"; fillMode: Image.TileVertically
+ }
+
+ Image {
+ objectName: "hTiling"; x: 225; height: 250; width: 550
+ source: "green.png"; fillMode: Image.TileHorizontally
+ }
+}
+
diff --git a/tests/auto/declarative/qsgimage/qsgimage.pro b/tests/auto/declarative/qsgimage/qsgimage.pro
new file mode 100644
index 0000000000..9c33889330
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/qsgimage.pro
@@ -0,0 +1,17 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui network
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/testhttpserver.h
+SOURCES += tst_qsgimage.cpp ../shared/testhttpserver.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgimage/tst_qsgimage.cpp b/tests/auto/declarative/qsgimage/tst_qsgimage.cpp
new file mode 100644
index 0000000000..e7366ff1b8
--- /dev/null
+++ b/tests/auto/declarative/qsgimage/tst_qsgimage.cpp
@@ -0,0 +1,776 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QTextDocument>
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QDir>
+
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qsgview.h>
+#include <private/qsgimage_p.h>
+#include <private/qsgimagebase_p.h>
+#include <private/qsgloader_p.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtTest/QSignalSpy>
+
+#include "../../../shared/util.h"
+#include "../shared/testhttpserver.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+#define SERVER_PORT 14451
+#define SERVER_ADDR "http://127.0.0.1:14451"
+
+class tst_qsgimage : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qsgimage();
+
+private slots:
+ void noSource();
+ void imageSource();
+ void imageSource_data();
+ void clearSource();
+ void resized();
+ void preserveAspectRatio();
+ void smooth();
+ void mirror();
+ void mirror_data();
+ void svg();
+ void geometry();
+ void geometry_data();
+ void big();
+ void tiling_QTBUG_6716();
+ void noLoading();
+ void paintedWidthHeight();
+ void sourceSize_QTBUG_14303();
+ void sourceSize_QTBUG_16389();
+ void nullPixmapPaint();
+ void testQtQuick11Attributes();
+ void testQtQuick11Attributes_data();
+
+private:
+ template<typename T>
+ T *findItem(QSGItem *parent, const QString &id, int index=-1);
+
+ QDeclarativeEngine engine;
+};
+
+tst_qsgimage::tst_qsgimage()
+{
+}
+
+void tst_qsgimage::noSource()
+{
+ QString componentStr = "import QtQuick 1.0\nImage { source: \"\" }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->source(), QUrl());
+ QVERIFY(obj->status() == QSGImage::Null);
+ QCOMPARE(obj->width(), 0.);
+ QCOMPARE(obj->height(), 0.);
+ QCOMPARE(obj->fillMode(), QSGImage::Stretch);
+ QCOMPARE(obj->progress(), 0.0);
+
+ delete obj;
+}
+
+void tst_qsgimage::imageSource_data()
+{
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<double>("width");
+ QTest::addColumn<double>("height");
+ QTest::addColumn<bool>("remote");
+ QTest::addColumn<bool>("async");
+ QTest::addColumn<bool>("cache");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("local") << QUrl::fromLocalFile(SRCDIR "/data/colors.png").toString() << 120.0 << 120.0 << false << false << true << "";
+ QTest::newRow("local no cache") << QUrl::fromLocalFile(SRCDIR "/data/colors.png").toString() << 120.0 << 120.0 << false << false << false << "";
+ QTest::newRow("local async") << QUrl::fromLocalFile(SRCDIR "/data/colors1.png").toString() << 120.0 << 120.0 << false << true << true << "";
+ QTest::newRow("local not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString() << 0.0 << 0.0 << false
+ << false << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString();
+ QTest::newRow("local async not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file-1.png").toString() << 0.0 << 0.0 << false
+ << true << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/no-such-file-1.png").toString();
+ QTest::newRow("remote") << SERVER_ADDR "/colors.png" << 120.0 << 120.0 << true << false << true << "";
+ QTest::newRow("remote redirected") << SERVER_ADDR "/oldcolors.png" << 120.0 << 120.0 << true << false << false << "";
+ QTest::newRow("remote svg") << SERVER_ADDR "/heart.svg" << 550.0 << 500.0 << true << false << false << "";
+ QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << 0.0 << 0.0 << true
+ << false << true << "file::2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found";
+
+}
+
+void tst_qsgimage::imageSource()
+{
+ QFETCH(QString, source);
+ QFETCH(double, width);
+ QFETCH(double, height);
+ QFETCH(bool, remote);
+ QFETCH(bool, async);
+ QFETCH(bool, cache);
+ QFETCH(QString, error);
+
+ TestHTTPServer server(SERVER_PORT);
+ if (remote) {
+ QVERIFY(server.isValid());
+ server.serveDirectory(SRCDIR "/data");
+ server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
+ }
+
+ if (!error.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
+
+ QString componentStr = "import QtQuick 1.1\nImage { source: \"" + source + "\"; asynchronous: "
+ + (async ? QLatin1String("true") : QLatin1String("false")) + "; cache: "
+ + (cache ? QLatin1String("true") : QLatin1String("false")) + " }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+
+ if (async)
+ QVERIFY(obj->asynchronous() == true);
+ else
+ QVERIFY(obj->asynchronous() == false);
+
+ if (cache)
+ QVERIFY(obj->cache() == true);
+ else
+ QVERIFY(obj->cache() == false);
+
+ if (remote || async)
+ QTRY_VERIFY(obj->status() == QSGImage::Loading);
+
+ QCOMPARE(obj->source(), remote ? source : QUrl(source));
+
+ if (error.isEmpty()) {
+ QTRY_VERIFY(obj->status() == QSGImage::Ready);
+ QCOMPARE(obj->width(), qreal(width));
+ QCOMPARE(obj->height(), qreal(height));
+ QCOMPARE(obj->fillMode(), QSGImage::Stretch);
+ QCOMPARE(obj->progress(), 1.0);
+ } else {
+ QTRY_VERIFY(obj->status() == QSGImage::Error);
+ }
+
+ delete obj;
+}
+
+void tst_qsgimage::clearSource()
+{
+ QString componentStr = "import QtQuick 1.0\nImage { source: srcImage }";
+ QDeclarativeContext *ctxt = engine.rootContext();
+ ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.png"));
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+ QVERIFY(obj->status() == QSGImage::Ready);
+ QCOMPARE(obj->width(), 120.);
+ QCOMPARE(obj->height(), 120.);
+ QCOMPARE(obj->progress(), 1.0);
+
+ ctxt->setContextProperty("srcImage", "");
+ QVERIFY(obj->source().isEmpty());
+ QVERIFY(obj->status() == QSGImage::Null);
+ QCOMPARE(obj->width(), 0.);
+ QCOMPARE(obj->height(), 0.);
+ QCOMPARE(obj->progress(), 0.0);
+
+ delete obj;
+}
+
+void tst_qsgimage::resized()
+{
+ QString componentStr = "import QtQuick 1.0\nImage { source: \"" SRCDIR "/data/colors.png\"; width: 300; height: 300 }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->width(), 300.);
+ QCOMPARE(obj->height(), 300.);
+ QCOMPARE(obj->fillMode(), QSGImage::Stretch);
+ delete obj;
+}
+
+
+void tst_qsgimage::preserveAspectRatio()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->show();
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/aspectratio.qml"));
+ QSGImage *image = qobject_cast<QSGImage*>(canvas->rootObject());
+ QVERIFY(image != 0);
+ image->setWidth(80.0);
+ QCOMPARE(image->width(), 80.);
+ QCOMPARE(image->height(), 80.);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/aspectratio.qml"));
+ image = qobject_cast<QSGImage*>(canvas->rootObject());
+ image->setHeight(60.0);
+ QVERIFY(image != 0);
+ QCOMPARE(image->height(), 60.);
+ QCOMPARE(image->width(), 60.);
+ delete canvas;
+}
+
+void tst_qsgimage::smooth()
+{
+ QString componentStr = "import QtQuick 1.0\nImage { source: \"" SRCDIR "/data/colors.png\"; smooth: true; width: 300; height: 300 }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->width(), 300.);
+ QCOMPARE(obj->height(), 300.);
+ QCOMPARE(obj->smooth(), true);
+ QCOMPARE(obj->fillMode(), QSGImage::Stretch);
+
+ delete obj;
+}
+
+void tst_qsgimage::mirror()
+{
+ QFETCH(int, fillMode);
+
+ qreal width = 300;
+ qreal height = 250;
+
+ QString src = QUrl::fromLocalFile(SRCDIR "/data/heart200.png").toString();
+ QString componentStr = "import QtQuick 1.1\nImage { source: \"" + src + "\"; }";
+
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+
+ obj->setProperty("width", width);
+ obj->setProperty("height", height);
+ obj->setFillMode((QSGImage::FillMode)fillMode);
+ obj->setProperty("mirror", true);
+
+ QGraphicsScene scene;
+ scene.addItem(qobject_cast<QSGItem *>(obj));
+ QPixmap screenshot(width, height);
+ screenshot.fill();
+ QPainter p_screenshot(&screenshot);
+ scene.render(&p_screenshot, QRect(0, 0, width, height), QRect(0, 0, width, height));
+
+ QPixmap srcPixmap;
+ QVERIFY(srcPixmap.load(SRCDIR "/data/heart200.png"));
+
+ QPixmap expected(width, height);
+ expected.fill();
+ QPainter p_e(&expected);
+ QTransform transform;
+ transform.translate(width, 0).scale(-1, 1.0);
+ p_e.setTransform(transform);
+
+ switch (fillMode) {
+ case QSGImage::Stretch:
+ p_e.drawPixmap(QRect(0, 0, width, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
+ break;
+ case QSGImage::PreserveAspectFit:
+ p_e.drawPixmap(QRect(25, 0, width / (width/height), height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
+ break;
+ case QSGImage::PreserveAspectCrop:
+ {
+ qreal ratio = width/srcPixmap.width(); // width is the longer side
+ QRect rect(0, 0, srcPixmap.width()*ratio, srcPixmap.height()*ratio);
+ rect.moveCenter(QRect(0, 0, width, height).center());
+ p_e.drawPixmap(rect, srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
+ break;
+ }
+ case QSGImage::Tile:
+ p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
+ break;
+ case QSGImage::TileVertically:
+ transform.scale(width / srcPixmap.width(), 1.0);
+ p_e.setTransform(transform);
+ p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
+ break;
+ case QSGImage::TileHorizontally:
+ transform.scale(1.0, height / srcPixmap.height());
+ p_e.setTransform(transform);
+ p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
+ break;
+ }
+
+ QCOMPARE(screenshot, expected);
+
+ delete obj;
+}
+
+void tst_qsgimage::mirror_data()
+{
+ QTest::addColumn<int>("fillMode");
+
+ QTest::newRow("Stretch") << int(QSGImage::Stretch);
+ QTest::newRow("PreserveAspectFit") << int(QSGImage::PreserveAspectFit);
+ QTest::newRow("PreserveAspectCrop") << int(QSGImage::PreserveAspectCrop);
+ QTest::newRow("Tile") << int(QSGImage::Tile);
+ QTest::newRow("TileVertically") << int(QSGImage::TileVertically);
+ QTest::newRow("TileHorizontally") << int(QSGImage::TileHorizontally);
+}
+
+void tst_qsgimage::svg()
+{
+ QString src = QUrl::fromLocalFile(SRCDIR "/data/heart.svg").toString();
+ QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; sourceSize.width: 300; sourceSize.height: 300 }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->pixmap().width(), 300);
+ QCOMPARE(obj->pixmap().height(), 300);
+ QCOMPARE(obj->width(), 300.0);
+ QCOMPARE(obj->height(), 300.0);
+#if defined(Q_OS_LINUX)
+ QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart.png"));
+#elif defined(Q_OS_WIN32)
+ QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart-win32.png"));
+#endif
+
+ obj->setSourceSize(QSize(200,200));
+
+ QCOMPARE(obj->pixmap().width(), 200);
+ QCOMPARE(obj->pixmap().height(), 200);
+ QCOMPARE(obj->width(), 200.0);
+ QCOMPARE(obj->height(), 200.0);
+#if defined(Q_OS_LINUX)
+ QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart200.png"));
+#elif defined(Q_OS_WIN32)
+ QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart200-win32.png"));
+#endif
+ delete obj;
+}
+
+void tst_qsgimage::geometry_data()
+{
+ QTest::addColumn<QString>("fillMode");
+ QTest::addColumn<bool>("explicitWidth");
+ QTest::addColumn<bool>("explicitHeight");
+ QTest::addColumn<double>("itemWidth");
+ QTest::addColumn<double>("paintedWidth");
+ QTest::addColumn<double>("boundingWidth");
+ QTest::addColumn<double>("itemHeight");
+ QTest::addColumn<double>("paintedHeight");
+ QTest::addColumn<double>("boundingHeight");
+
+ // tested image has width 200, height 100
+
+ // bounding rect and item rect are equal with fillMode PreserveAspectFit, painted rect may be smaller if the aspect ratio doesn't match
+ QTest::newRow("PreserveAspectFit") << "PreserveAspectFit" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
+ QTest::newRow("PreserveAspectFit explicit width 300") << "PreserveAspectFit" << true << false << 300.0 << 200.0 << 300.0 << 100.0 << 100.0 << 100.0;
+ QTest::newRow("PreserveAspectFit explicit height 400") << "PreserveAspectFit" << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 100.0 << 400.0;
+ QTest::newRow("PreserveAspectFit explicit width 300, height 400") << "PreserveAspectFit" << true << true << 300.0 << 300.0 << 300.0 << 400.0 << 150.0 << 400.0;
+
+ // bounding rect and painted rect are equal with fillMode PreserveAspectCrop, item rect may be smaller if the aspect ratio doesn't match
+ QTest::newRow("PreserveAspectCrop") << "PreserveAspectCrop" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
+ QTest::newRow("PreserveAspectCrop explicit width 300") << "PreserveAspectCrop" << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 150.0 << 150.0;
+ QTest::newRow("PreserveAspectCrop explicit height 400") << "PreserveAspectCrop" << false << true << 200.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
+ QTest::newRow("PreserveAspectCrop explicit width 300, height 400") << "PreserveAspectCrop" << true << true << 300.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
+
+ // bounding rect, painted rect and item rect are equal in stretching and tiling images
+ QStringList fillModes;
+ fillModes << "Stretch" << "Tile" << "TileVertically" << "TileHorizontally";
+ foreach (QString fillMode, fillModes) {
+ QTest::newRow(fillMode.toLatin1()) << fillMode << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
+ QTest::newRow(QString(fillMode + " explicit width 300").toLatin1()) << fillMode << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 100.0 << 100.0;
+ QTest::newRow(QString(fillMode + " explicit height 400").toLatin1()) << fillMode << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 400.0 << 400.0;
+ QTest::newRow(QString(fillMode + " explicit width 300, height 400").toLatin1()) << fillMode << true << true << 300.0 << 300.0 << 300.0 << 400.0 << 400.0 << 400.0;
+ }
+}
+
+void tst_qsgimage::geometry()
+{
+ QFETCH(QString, fillMode);
+ QFETCH(bool, explicitWidth);
+ QFETCH(bool, explicitHeight);
+ QFETCH(double, itemWidth);
+ QFETCH(double, itemHeight);
+ QFETCH(double, paintedWidth);
+ QFETCH(double, paintedHeight);
+ QFETCH(double, boundingWidth);
+ QFETCH(double, boundingHeight);
+
+ QString src = QUrl::fromLocalFile(SRCDIR "/data/rect.png").toString();
+ QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; fillMode: Image." + fillMode + "; ";
+
+ if (explicitWidth)
+ componentStr.append("width: 300; ");
+ if (explicitHeight)
+ componentStr.append("height: 400; ");
+ componentStr.append("}");
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+
+ QCOMPARE(obj->width(), itemWidth);
+ QCOMPARE(obj->paintedWidth(), paintedWidth);
+ QCOMPARE(obj->boundingRect().width(), boundingWidth);
+
+ QCOMPARE(obj->height(), itemHeight);
+ QCOMPARE(obj->paintedHeight(), paintedHeight);
+ QCOMPARE(obj->boundingRect().height(), boundingHeight);
+ delete obj;
+}
+
+void tst_qsgimage::big()
+{
+ // If the JPEG loader does not implement scaling efficiently, it would
+ // have to build a 400 MB image. That would be a bug in the JPEG loader.
+
+ QString src = QUrl::fromLocalFile(SRCDIR "/data/big.jpeg").toString();
+ QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; width: 100; sourceSize.height: 256 }";
+
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->pixmap().width(), 256);
+ QCOMPARE(obj->pixmap().height(), 256);
+ QCOMPARE(obj->width(), 100.0);
+ QCOMPARE(obj->height(), 256.0);
+ QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/big256.png"));
+
+ delete obj;
+}
+
+void tst_qsgimage::tiling_QTBUG_6716()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/tiling.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QSGImage *vTiling = findItem<QSGImage>(canvas->rootObject(), "vTiling");
+ QSGImage *hTiling = findItem<QSGImage>(canvas->rootObject(), "hTiling");
+
+ QVERIFY(vTiling != 0);
+ QVERIFY(hTiling != 0);
+
+ {
+ QPixmap pm(vTiling->width(), vTiling->height());
+ QPainter p(&pm);
+ vTiling->paint(&p, 0, 0);
+
+ QImage img = pm.toImage();
+ for (int x = 0; x < vTiling->width(); ++x) {
+ for (int y = 0; y < vTiling->height(); ++y) {
+ QVERIFY(img.pixel(x, y) == qRgb(0, 255, 0));
+ }
+ }
+ }
+
+ {
+ QPixmap pm(hTiling->width(), hTiling->height());
+ QPainter p(&pm);
+ hTiling->paint(&p, 0, 0);
+
+ QImage img = pm.toImage();
+ for (int x = 0; x < hTiling->width(); ++x) {
+ for (int y = 0; y < hTiling->height(); ++y) {
+ QVERIFY(img.pixel(x, y) == qRgb(0, 255, 0));
+ }
+ }
+ }
+
+ delete canvas;
+}
+
+void tst_qsgimage::noLoading()
+{
+ TestHTTPServer server(SERVER_PORT);
+ QVERIFY(server.isValid());
+ server.serveDirectory(SRCDIR "/data");
+ server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
+
+ QString componentStr = "import QtQuick 1.0\nImage { source: srcImage }";
+ QDeclarativeContext *ctxt = engine.rootContext();
+ ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/heart.png"));
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+ QVERIFY(obj->status() == QSGImage::Ready);
+
+ QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &)));
+ QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal)));
+ QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QSGImageBase::Status)));
+
+ // Loading local file
+ ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.png"));
+ QTRY_VERIFY(obj->status() == QSGImage::Ready);
+ QTRY_VERIFY(obj->progress() == 1.0);
+ QTRY_COMPARE(sourceSpy.count(), 1);
+ QTRY_COMPARE(progressSpy.count(), 0);
+ QTRY_COMPARE(statusSpy.count(), 0);
+
+ // Loading remote file
+ ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/heart200.png");
+ QTRY_VERIFY(obj->status() == QSGImage::Loading);
+ QTRY_VERIFY(obj->progress() == 0.0);
+ QTRY_VERIFY(obj->status() == QSGImage::Ready);
+ QTRY_VERIFY(obj->progress() == 1.0);
+ QTRY_COMPARE(sourceSpy.count(), 2);
+ QTRY_COMPARE(progressSpy.count(), 2);
+ QTRY_COMPARE(statusSpy.count(), 2);
+
+ // Loading remote file again - should not go through 'Loading' state.
+ ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.png"));
+ ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/heart200.png");
+ QTRY_VERIFY(obj->status() == QSGImage::Ready);
+ QTRY_VERIFY(obj->progress() == 1.0);
+ QTRY_COMPARE(sourceSpy.count(), 4);
+ QTRY_COMPARE(progressSpy.count(), 2);
+ QTRY_COMPARE(statusSpy.count(), 2);
+
+ delete obj;
+}
+
+void tst_qsgimage::paintedWidthHeight()
+{
+ {
+ QString src = QUrl::fromLocalFile(SRCDIR "/data/heart.png").toString();
+ QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; width: 200; height: 25; fillMode: Image.PreserveAspectFit }";
+
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->pixmap().width(), 300);
+ QCOMPARE(obj->pixmap().height(), 300);
+ QCOMPARE(obj->width(), 200.0);
+ QCOMPARE(obj->height(), 25.0);
+ QCOMPARE(obj->paintedWidth(), 25.0);
+ QCOMPARE(obj->paintedHeight(), 25.0);
+ QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart.png"));
+
+ delete obj;
+ }
+
+ {
+ QString src = QUrl::fromLocalFile(SRCDIR "/data/heart.png").toString();
+ QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; width: 26; height: 175; fillMode: Image.PreserveAspectFit }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->pixmap().width(), 300);
+ QCOMPARE(obj->pixmap().height(), 300);
+ QCOMPARE(obj->width(), 26.0);
+ QCOMPARE(obj->height(), 175.0);
+ QCOMPARE(obj->paintedWidth(), 26.0);
+ QCOMPARE(obj->paintedHeight(), 26.0);
+ QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart.png"));
+
+ delete obj;
+ }
+}
+
+void tst_qsgimage::sourceSize_QTBUG_14303()
+{
+ QString componentStr = "import QtQuick 1.0\nImage { source: srcImage }";
+ QDeclarativeContext *ctxt = engine.rootContext();
+ ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/heart200.png"));
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *obj = qobject_cast<QSGImage*>(component.create());
+
+ QSignalSpy sourceSizeSpy(obj, SIGNAL(sourceSizeChanged()));
+
+ QTRY_VERIFY(obj != 0);
+ QTRY_VERIFY(obj->status() == QSGImage::Ready);
+
+ QTRY_COMPARE(obj->sourceSize().width(), 200);
+ QTRY_COMPARE(obj->sourceSize().height(), 200);
+ QTRY_COMPARE(sourceSizeSpy.count(), 0);
+
+ ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.png"));
+ QTRY_COMPARE(obj->sourceSize().width(), 120);
+ QTRY_COMPARE(obj->sourceSize().height(), 120);
+ QTRY_COMPARE(sourceSizeSpy.count(), 1);
+
+ ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/heart200.png"));
+ QTRY_COMPARE(obj->sourceSize().width(), 200);
+ QTRY_COMPARE(obj->sourceSize().height(), 200);
+ QTRY_COMPARE(sourceSizeSpy.count(), 2);
+
+ delete obj;
+}
+
+void tst_qsgimage::sourceSize_QTBUG_16389()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/qtbug_16389.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QSGImage *image = findItem<QSGImage>(canvas->rootObject(), "iconImage");
+ QSGItem *handle = findItem<QSGItem>(canvas->rootObject(), "blueHandle");
+
+ QCOMPARE(image->sourceSize().width(), 200);
+ QCOMPARE(image->sourceSize().height(), 200);
+ QCOMPARE(image->paintedWidth(), 0.0);
+ QCOMPARE(image->paintedHeight(), 0.0);
+
+ handle->setY(20);
+
+ QCOMPARE(image->sourceSize().width(), 200);
+ QCOMPARE(image->sourceSize().height(), 200);
+ QCOMPARE(image->paintedWidth(), 20.0);
+ QCOMPARE(image->paintedHeight(), 20.0);
+}
+
+static int numberOfWarnings = 0;
+static void checkWarnings(QtMsgType, const char *)
+{
+ numberOfWarnings++;
+}
+
+// QTBUG-15690
+void tst_qsgimage::nullPixmapPaint()
+{
+ QString componentStr = QString("import QtQuick 1.0\nImage { width: 10; height:10; fillMode: Image.PreserveAspectFit; source: \"")
+ + SERVER_ADDR + QString("/no-such-file.png\" }");
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGImage *image = qobject_cast<QSGImage*>(component.create());
+
+ QTRY_VERIFY(image != 0);
+
+ QtMsgHandler previousMsgHandler = qInstallMsgHandler(checkWarnings);
+
+ QPixmap pm(100, 100);
+ QPainter p(&pm);
+
+ // used to print "QTransform::translate with NaN called"
+ image->paint(&p, 0, 0);
+ qInstallMsgHandler(previousMsgHandler);
+ QVERIFY(numberOfWarnings == 0);
+ delete image;
+}
+
+void tst_qsgimage::testQtQuick11Attributes()
+{
+ QFETCH(QString, code);
+ QFETCH(QString, warning);
+ QFETCH(QString, error);
+
+ QDeclarativeEngine engine;
+ QObject *obj;
+
+ QDeclarativeComponent valid(&engine);
+ valid.setData("import QtQuick 1.1; Image { " + code.toUtf8() + " }", QUrl(""));
+ obj = valid.create();
+ QVERIFY(obj);
+ QVERIFY(valid.errorString().isEmpty());
+ delete obj;
+
+ QDeclarativeComponent invalid(&engine);
+ invalid.setData("import QtQuick 1.0; Image { " + code.toUtf8() + " }", QUrl(""));
+ QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
+ obj = invalid.create();
+ QCOMPARE(invalid.errorString(), error);
+ delete obj;
+}
+
+void tst_qsgimage::testQtQuick11Attributes_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("mirror") << "mirror: true"
+ << "QDeclarativeComponent: Component is not ready"
+ << ":1 \"Image.mirror\" is not available in QtQuick 1.0.\n";
+
+ QTest::newRow("cache") << "cache: true"
+ << "QDeclarativeComponent: Component is not ready"
+ << ":1 \"Image.cache\" is not available in QtQuick 1.0.\n";
+}
+
+/*
+ Find an item with the specified objectName. If index is supplied then the
+ item must also evaluate the {index} expression equal to index
+*/
+template<typename T>
+T *tst_qsgimage::findItem(QSGItem *parent, const QString &objectName, int index)
+{
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->childItems().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ if (index != -1) {
+ QDeclarativeExpression e(qmlContext(item), item, "index");
+ if (e.evaluate().toInt() == index)
+ return static_cast<T*>(item);
+ } else {
+ return static_cast<T*>(item);
+ }
+ }
+ item = findItem<T>(item, objectName, index);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+}
+
+QTEST_MAIN(tst_qsgimage)
+
+#include "tst_qsgimage.moc"
diff --git a/tests/auto/declarative/qsgitem/qsgitem.pro b/tests/auto/declarative/qsgitem/qsgitem.pro
new file mode 100644
index 0000000000..6c659a395f
--- /dev/null
+++ b/tests/auto/declarative/qsgitem/qsgitem.pro
@@ -0,0 +1,7 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative
+SOURCES += tst_qsgitem.cpp
+
+macx:CONFIG -= app_bundle
+
+CONFIG += parallel_test
diff --git a/tests/auto/declarative/qsgitem/tst_qsgitem.cpp b/tests/auto/declarative/qsgitem/tst_qsgitem.cpp
new file mode 100644
index 0000000000..746b186c1e
--- /dev/null
+++ b/tests/auto/declarative/qsgitem/tst_qsgitem.cpp
@@ -0,0 +1,787 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+
+#include "qsgitem.h"
+#include "qsgcanvas.h"
+#include "private/qsgfocusscope_p.h"
+#include <QDebug>
+
+class TestItem : public QSGItem
+{
+Q_OBJECT
+public:
+ TestItem(QSGItem *parent = 0) : QSGItem(parent), focused(false), pressCount(0), releaseCount(0) {}
+
+ bool focused;
+ int pressCount;
+ int releaseCount;
+protected:
+ virtual void focusInEvent(QFocusEvent *) { Q_ASSERT(!focused); focused = true; }
+ virtual void focusOutEvent(QFocusEvent *) { Q_ASSERT(focused); focused = false; }
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) { event->accept(); ++pressCount; }
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { event->accept(); ++releaseCount; }
+};
+
+class TestFocusScope : public QSGFocusScope
+{
+Q_OBJECT
+public:
+ TestFocusScope(QSGItem *parent = 0) : QSGFocusScope(parent), focused(false) {}
+
+ bool focused;
+protected:
+ virtual void focusInEvent(QFocusEvent *) { Q_ASSERT(!focused); focused = true; }
+ virtual void focusOutEvent(QFocusEvent *) { Q_ASSERT(focused); focused = false; }
+};
+
+class tst_qsgitem : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qsgitem();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void noCanvas();
+ void simpleFocus();
+ void scopedFocus();
+ void addedToCanvas();
+ void changeParent();
+
+ void constructor();
+ void setParentItem();
+
+ void visible();
+ void enabled();
+
+ void mouseGrab();
+};
+
+tst_qsgitem::tst_qsgitem()
+{
+}
+
+void tst_qsgitem::initTestCase()
+{
+}
+
+void tst_qsgitem::cleanupTestCase()
+{
+}
+
+// Focus has no effect when outside a canvas
+void tst_qsgitem::noCanvas()
+{
+ QSGItem *root = new TestItem;
+ QSGItem *child = new TestItem(root);
+ QSGItem *scope = new TestItem(root);
+ QSGFocusScope *scopedChild = new TestFocusScope(scope);
+ QSGFocusScope *scopedChild2 = new TestFocusScope(scope);
+
+ QCOMPARE(root->hasFocus(), false);
+ QCOMPARE(child->hasFocus(), false);
+ QCOMPARE(scope->hasFocus(), false);
+ QCOMPARE(scopedChild->hasFocus(), false);
+ QCOMPARE(scopedChild2->hasFocus(), false);
+
+ root->setFocus(true);
+ scope->setFocus(true);
+ scopedChild2->setFocus(true);
+ QCOMPARE(root->hasFocus(), true);
+ QCOMPARE(child->hasFocus(), false);
+ QCOMPARE(scope->hasFocus(), true);
+ QCOMPARE(scopedChild->hasFocus(), false);
+ QCOMPARE(scopedChild2->hasFocus(), true);
+
+ root->setFocus(false);
+ child->setFocus(true);
+ scopedChild->setFocus(true);
+ scope->setFocus(false);
+ QCOMPARE(root->hasFocus(), false);
+ QCOMPARE(child->hasFocus(), true);
+ QCOMPARE(scope->hasFocus(), false);
+ QCOMPARE(scopedChild->hasFocus(), true);
+ QCOMPARE(scopedChild2->hasFocus(), true);
+
+ delete root;
+}
+
+struct FocusData {
+ FocusData() : focus(false), activeFocus(false) {}
+
+ void set(bool f, bool af) { focus = f; activeFocus = af; }
+ bool focus;
+ bool activeFocus;
+};
+struct FocusState : public QHash<QSGItem *, FocusData>
+{
+ FocusState() : activeFocusItem(0) {}
+ FocusState &operator<<(QSGItem *item) {
+ insert(item, FocusData());
+ return *this;
+ }
+
+ void active(QSGItem *i) {
+ activeFocusItem = i;
+ }
+ QSGItem *activeFocusItem;
+};
+
+#define FVERIFY() \
+ do { \
+ if (focusState.activeFocusItem) { \
+ QCOMPARE(canvas.activeFocusItem(), focusState.activeFocusItem); \
+ if (qobject_cast<TestItem *>(canvas.activeFocusItem())) \
+ QCOMPARE(qobject_cast<TestItem *>(canvas.activeFocusItem())->focused, true); \
+ else if (qobject_cast<TestFocusScope *>(canvas.activeFocusItem())) \
+ QCOMPARE(qobject_cast<TestFocusScope *>(canvas.activeFocusItem())->focused, true); \
+ } else { \
+ QCOMPARE(canvas.activeFocusItem(), canvas.rootItem()); \
+ } \
+ for(QHash<QSGItem *, FocusData>::Iterator iter = focusState.begin(); \
+ iter != focusState.end(); \
+ iter++) { \
+ QCOMPARE(iter.key()->hasFocus(), iter.value().focus); \
+ QCOMPARE(iter.key()->hasActiveFocus(), iter.value().activeFocus); \
+ } \
+ } while(false)
+
+// Tests a simple set of top-level scoped items
+void tst_qsgitem::simpleFocus()
+{
+ QSGCanvas canvas;
+
+ QSGItem *l1c1 = new TestItem(canvas.rootItem());
+ QSGItem *l1c2 = new TestItem(canvas.rootItem());
+ QSGItem *l1c3 = new TestItem(canvas.rootItem());
+
+ QSGItem *l2c1 = new TestItem(l1c1);
+ QSGItem *l2c2 = new TestItem(l1c1);
+ QSGItem *l2c3 = new TestItem(l1c3);
+
+ FocusState focusState;
+ focusState << l1c1 << l1c2 << l1c3
+ << l2c1 << l2c2 << l2c3;
+ FVERIFY();
+
+ l1c1->setFocus(true);
+ focusState[l1c1].set(true, true);
+ focusState.active(l1c1);
+ FVERIFY();
+
+ l2c3->setFocus(true);
+ focusState[l1c1].set(false, false);
+ focusState[l2c3].set(true, true);
+ focusState.active(l2c3);
+ FVERIFY();
+
+ l1c3->setFocus(true);
+ focusState[l2c3].set(false, false);
+ focusState[l1c3].set(true, true);
+ focusState.active(l1c3);
+ FVERIFY();
+
+ l1c2->setFocus(false);
+ FVERIFY();
+
+ l1c3->setFocus(false);
+ focusState[l1c3].set(false, false);
+ focusState.active(0);
+ FVERIFY();
+
+ l2c1->setFocus(true);
+ focusState[l2c1].set(true, true);
+ focusState.active(l2c1);
+ FVERIFY();
+}
+
+// Items with a focus scope
+void tst_qsgitem::scopedFocus()
+{
+ QSGCanvas canvas;
+
+ QSGItem *l1c1 = new TestItem(canvas.rootItem());
+ QSGItem *l1c2 = new TestItem(canvas.rootItem());
+ QSGItem *l1c3 = new TestItem(canvas.rootItem());
+
+ QSGItem *l2c1 = new TestItem(l1c1);
+ QSGItem *l2c2 = new TestItem(l1c1);
+ QSGItem *l2c3 = new TestFocusScope(l1c3);
+
+ QSGItem *l3c1 = new TestItem(l2c3);
+ QSGItem *l3c2 = new TestFocusScope(l2c3);
+
+ QSGItem *l4c1 = new TestItem(l3c2);
+ QSGItem *l4c2 = new TestItem(l3c2);
+
+ FocusState focusState;
+ focusState << l1c1 << l1c2 << l1c3
+ << l2c1 << l2c2 << l2c3
+ << l3c1 << l3c2
+ << l4c1 << l4c2;
+ FVERIFY();
+
+ l4c2->setFocus(true);
+ focusState[l4c2].set(true, false);
+ FVERIFY();
+
+ l4c1->setFocus(true);
+ focusState[l4c2].set(false, false);
+ focusState[l4c1].set(true, false);
+ FVERIFY();
+
+ l1c1->setFocus(true);
+ focusState[l1c1].set(true, true);
+ focusState.active(l1c1);
+ FVERIFY();
+
+ l3c2->setFocus(true);
+ focusState[l3c2].set(true, false);
+ FVERIFY();
+
+ l2c3->setFocus(true);
+ focusState[l1c1].set(false, false);
+ focusState[l2c3].set(true, true);
+ focusState[l3c2].set(true, true);
+ focusState[l4c1].set(true, true);
+ focusState.active(l4c1);
+ FVERIFY();
+
+ l3c2->setFocus(false);
+ focusState[l3c2].set(false, false);
+ focusState[l4c1].set(true, false);
+ focusState.active(l2c3);
+ FVERIFY();
+
+ l3c2->setFocus(true);
+ focusState[l3c2].set(true, true);
+ focusState[l4c1].set(true, true);
+ focusState.active(l4c1);
+ FVERIFY();
+
+ l4c1->setFocus(false);
+ focusState[l4c1].set(false, false);
+ focusState.active(l3c2);
+ FVERIFY();
+
+ l1c3->setFocus(true);
+ focusState[l1c3].set(true, true);
+ focusState[l2c3].set(false, false);
+ focusState[l3c2].set(true, false);
+ focusState.active(l1c3);
+ FVERIFY();
+}
+
+// Tests focus corrects itself when a tree is added to a canvas for the first time
+void tst_qsgitem::addedToCanvas()
+{
+ {
+ QSGCanvas canvas;
+
+ QSGItem *item = new TestItem;
+
+ FocusState focusState;
+ focusState << item;
+
+ item->setFocus(true);
+ focusState[item].set(true, false);
+ FVERIFY();
+
+ item->setParentItem(canvas.rootItem());
+ focusState[item].set(true, true);
+ focusState.active(item);
+ FVERIFY();
+ }
+
+ {
+ QSGCanvas canvas;
+
+ QSGItem *item = new TestItem(canvas.rootItem());
+
+ QSGItem *tree = new TestItem;
+ QSGItem *c1 = new TestItem(tree);
+ QSGItem *c2 = new TestItem(tree);
+
+ FocusState focusState;
+ focusState << item << tree << c1 << c2;
+
+ item->setFocus(true);
+ c1->setFocus(true);
+ c2->setFocus(true);
+ focusState[item].set(true, true);
+ focusState[c1].set(true, false);
+ focusState[c2].set(true, false);
+ focusState.active(item);
+ FVERIFY();
+
+ tree->setParentItem(item);
+ focusState[c1].set(false, false);
+ focusState[c2].set(false, false);
+ FVERIFY();
+ }
+
+ {
+ QSGCanvas canvas;
+
+ QSGItem *tree = new TestItem;
+ QSGItem *c1 = new TestItem(tree);
+ QSGItem *c2 = new TestItem(tree);
+
+ FocusState focusState;
+ focusState << tree << c1 << c2;
+ c1->setFocus(true);
+ c2->setFocus(true);
+ focusState[c1].set(true, false);
+ focusState[c2].set(true, false);
+ FVERIFY();
+
+ tree->setParentItem(canvas.rootItem());
+ focusState[c1].set(true, true);
+ focusState[c2].set(false, false);
+ focusState.active(c1);
+ FVERIFY();
+ }
+
+ {
+ QSGCanvas canvas;
+ QSGItem *tree = new TestFocusScope;
+ QSGItem *c1 = new TestItem(tree);
+ QSGItem *c2 = new TestItem(tree);
+
+ FocusState focusState;
+ focusState << tree << c1 << c2;
+ c1->setFocus(true);
+ c2->setFocus(true);
+ focusState[c1].set(true, false);
+ focusState[c2].set(true, false);
+ FVERIFY();
+
+ tree->setParentItem(canvas.rootItem());
+ focusState[c1].set(true, false);
+ focusState[c2].set(false, false);
+ FVERIFY();
+
+ tree->setFocus(true);
+ focusState[tree].set(true, true);
+ focusState[c1].set(true, true);
+ focusState.active(c1);
+ FVERIFY();
+ }
+
+ {
+ QSGCanvas canvas;
+ QSGItem *tree = new TestFocusScope;
+ QSGItem *c1 = new TestItem(tree);
+ QSGItem *c2 = new TestItem(tree);
+
+ FocusState focusState;
+ focusState << tree << c1 << c2;
+ tree->setFocus(true);
+ c1->setFocus(true);
+ c2->setFocus(true);
+ focusState[tree].set(true, false);
+ focusState[c1].set(true, false);
+ focusState[c2].set(true, false);
+ FVERIFY();
+
+ tree->setParentItem(canvas.rootItem());
+ focusState[tree].set(true, true);
+ focusState[c1].set(true, true);
+ focusState[c2].set(false, false);
+ focusState.active(c1);
+ FVERIFY();
+ }
+
+ {
+ QSGCanvas canvas;
+ QSGItem *child = new TestItem(canvas.rootItem());
+ QSGItem *tree = new TestFocusScope;
+ QSGItem *c1 = new TestItem(tree);
+ QSGItem *c2 = new TestItem(tree);
+
+ FocusState focusState;
+ focusState << child << tree << c1 << c2;
+ child->setFocus(true);
+ tree->setFocus(true);
+ c1->setFocus(true);
+ c2->setFocus(true);
+ focusState[child].set(true, true);
+ focusState[tree].set(true, false);
+ focusState[c1].set(true, false);
+ focusState[c2].set(true, false);
+ focusState.active(child);
+ FVERIFY();
+
+ tree->setParentItem(canvas.rootItem());
+ focusState[tree].set(false, false);
+ focusState[c1].set(true, false);
+ focusState[c2].set(false, false);
+ FVERIFY();
+
+ tree->setFocus(true);
+ focusState[child].set(false, false);
+ focusState[tree].set(true, true);
+ focusState[c1].set(true, true);
+ focusState.active(c1);
+ FVERIFY();
+ }
+}
+
+void tst_qsgitem::changeParent()
+{
+ // Parent to no parent
+ {
+ QSGCanvas canvas;
+ QSGItem *child = new TestItem(canvas.rootItem());
+
+ FocusState focusState;
+ focusState << child;
+ FVERIFY();
+
+ child->setFocus(true);
+ focusState[child].set(true, true);
+ focusState.active(child);
+ FVERIFY();
+
+ child->setParentItem(0);
+ focusState[child].set(true, false);
+ focusState.active(0);
+ FVERIFY();
+ }
+
+ // Different parent, same focus scope
+ {
+ QSGCanvas canvas;
+ QSGItem *child = new TestItem(canvas.rootItem());
+ QSGItem *child2 = new TestItem(canvas.rootItem());
+
+ FocusState focusState;
+ focusState << child << child2;
+ FVERIFY();
+
+ child->setFocus(true);
+ focusState[child].set(true, true);
+ focusState.active(child);
+ FVERIFY();
+
+ child->setParentItem(child2);
+ FVERIFY();
+ }
+
+ // Different parent, different focus scope
+ {
+ QSGCanvas canvas;
+ QSGItem *child = new TestItem(canvas.rootItem());
+ QSGItem *child2 = new TestFocusScope(canvas.rootItem());
+ QSGItem *item = new TestItem(child);
+
+ FocusState focusState;
+ focusState << child << child2 << item;
+ FVERIFY();
+
+ item->setFocus(true);
+ focusState[item].set(true, true);
+ focusState.active(item);
+ FVERIFY();
+
+ item->setParentItem(child2);
+ focusState[item].set(true, false);
+ focusState.active(0);
+ FVERIFY();
+ }
+ {
+ QSGCanvas canvas;
+ QSGItem *child = new TestItem(canvas.rootItem());
+ QSGItem *child2 = new TestFocusScope(canvas.rootItem());
+ QSGItem *item = new TestItem(child2);
+
+ FocusState focusState;
+ focusState << child << child2 << item;
+ FVERIFY();
+
+ item->setFocus(true);
+ focusState[item].set(true, false);
+ focusState.active(0);
+ FVERIFY();
+
+ item->setParentItem(child);
+ focusState[item].set(true, true);
+ focusState.active(item);
+ FVERIFY();
+ }
+ {
+ QSGCanvas canvas;
+ QSGItem *child = new TestItem(canvas.rootItem());
+ QSGItem *child2 = new TestFocusScope(canvas.rootItem());
+ QSGItem *item = new TestItem(child2);
+
+ FocusState focusState;
+ focusState << child << child2 << item;
+ FVERIFY();
+
+ child->setFocus(true);
+ item->setFocus(true);
+ focusState[child].set(true, true);
+ focusState[item].set(true, false);
+ focusState.active(child);
+ FVERIFY();
+
+ item->setParentItem(child);
+ focusState[item].set(false, false);
+ FVERIFY();
+ }
+
+}
+
+void tst_qsgitem::constructor()
+{
+ QSGItem *root = new QSGItem;
+ QVERIFY(root->parent() == 0);
+ QVERIFY(root->parentItem() == 0);
+
+ QSGItem *child1 = new QSGItem(root);
+ QVERIFY(child1->parent() == root);
+ QVERIFY(child1->parentItem() == root);
+ QCOMPARE(root->childItems().count(), 1);
+ QCOMPARE(root->childItems().at(0), child1);
+
+ QSGItem *child2 = new QSGItem(root);
+ QVERIFY(child2->parent() == root);
+ QVERIFY(child2->parentItem() == root);
+ QCOMPARE(root->childItems().count(), 2);
+ QCOMPARE(root->childItems().at(0), child1);
+ QCOMPARE(root->childItems().at(1), child2);
+
+ delete root;
+}
+
+void tst_qsgitem::setParentItem()
+{
+ QSGItem *root = new QSGItem;
+ QVERIFY(root->parent() == 0);
+ QVERIFY(root->parentItem() == 0);
+
+ QSGItem *child1 = new QSGItem;
+ QVERIFY(child1->parent() == 0);
+ QVERIFY(child1->parentItem() == 0);
+
+ child1->setParentItem(root);
+ QVERIFY(child1->parent() == 0);
+ QVERIFY(child1->parentItem() == root);
+ QCOMPARE(root->childItems().count(), 1);
+ QCOMPARE(root->childItems().at(0), child1);
+
+ QSGItem *child2 = new QSGItem;
+ QVERIFY(child2->parent() == 0);
+ QVERIFY(child2->parentItem() == 0);
+ child2->setParentItem(root);
+ QVERIFY(child2->parent() == 0);
+ QVERIFY(child2->parentItem() == root);
+ QCOMPARE(root->childItems().count(), 2);
+ QCOMPARE(root->childItems().at(0), child1);
+ QCOMPARE(root->childItems().at(1), child2);
+
+ child1->setParentItem(0);
+ QVERIFY(child1->parent() == 0);
+ QVERIFY(child1->parentItem() == 0);
+ QCOMPARE(root->childItems().count(), 1);
+ QCOMPARE(root->childItems().at(0), child2);
+
+ delete root;
+
+ QVERIFY(child1->parent() == 0);
+ QVERIFY(child1->parentItem() == 0);
+ QVERIFY(child2->parent() == 0);
+ QVERIFY(child2->parentItem() == 0);
+
+ delete child1;
+ delete child2;
+}
+
+void tst_qsgitem::visible()
+{
+ QSGItem *root = new QSGItem;
+
+ QSGItem *child1 = new QSGItem;
+ child1->setParentItem(root);
+
+ QSGItem *child2 = new QSGItem;
+ child2->setParentItem(root);
+
+ QVERIFY(child1->isVisible());
+ QVERIFY(child2->isVisible());
+
+ root->setVisible(false);
+ QVERIFY(!child1->isVisible());
+ QVERIFY(!child2->isVisible());
+
+ root->setVisible(true);
+ QVERIFY(child1->isVisible());
+ QVERIFY(child2->isVisible());
+
+ child1->setVisible(false);
+ QVERIFY(!child1->isVisible());
+ QVERIFY(child2->isVisible());
+
+ child2->setParentItem(child1);
+ QVERIFY(!child1->isVisible());
+ QVERIFY(!child2->isVisible());
+
+ child2->setParentItem(root);
+ QVERIFY(!child1->isVisible());
+ QVERIFY(child2->isVisible());
+
+ delete root;
+ delete child1;
+ delete child2;
+}
+
+void tst_qsgitem::enabled()
+{
+ QSGItem *root = new QSGItem;
+
+ QSGItem *child1 = new QSGItem;
+ child1->setParentItem(root);
+
+ QSGItem *child2 = new QSGItem;
+ child2->setParentItem(root);
+
+ QVERIFY(child1->isEnabled());
+ QVERIFY(child2->isEnabled());
+
+ root->setEnabled(false);
+ QVERIFY(!child1->isEnabled());
+ QVERIFY(!child2->isEnabled());
+
+ root->setEnabled(true);
+ QVERIFY(child1->isEnabled());
+ QVERIFY(child2->isEnabled());
+
+ child1->setEnabled(false);
+ QVERIFY(!child1->isEnabled());
+ QVERIFY(child2->isEnabled());
+
+ child2->setParentItem(child1);
+ QVERIFY(!child1->isEnabled());
+ QVERIFY(!child2->isEnabled());
+
+ child2->setParentItem(root);
+ QVERIFY(!child1->isEnabled());
+ QVERIFY(child2->isEnabled());
+
+ delete root;
+ delete child1;
+ delete child2;
+}
+
+void tst_qsgitem::mouseGrab()
+{
+ QSGCanvas *canvas = new QSGCanvas;
+ canvas->resize(200, 200);
+ canvas->show();
+
+ TestItem *child1 = new TestItem;
+ child1->setAcceptedMouseButtons(Qt::LeftButton);
+ child1->setSize(QSizeF(200, 100));
+ child1->setParentItem(canvas->rootItem());
+
+ TestItem *child2 = new TestItem;
+ child2->setAcceptedMouseButtons(Qt::LeftButton);
+ child2->setY(100);
+ child2->setSize(QSizeF(200, 100));
+ child2->setParentItem(canvas->rootItem());
+
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
+ QVERIFY(canvas->mouseGrabberItem() == child1);
+ QCOMPARE(child1->pressCount, 1);
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
+ QVERIFY(canvas->mouseGrabberItem() == 0);
+ QCOMPARE(child1->releaseCount, 1);
+
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
+ QVERIFY(canvas->mouseGrabberItem() == child1);
+ QCOMPARE(child1->pressCount, 2);
+ child1->setEnabled(false);
+ QVERIFY(canvas->mouseGrabberItem() == 0);
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
+ QCOMPARE(child1->releaseCount, 1);
+ child1->setEnabled(true);
+
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
+ QVERIFY(canvas->mouseGrabberItem() == child1);
+ QCOMPARE(child1->pressCount, 3);
+ child1->setVisible(false);
+ QVERIFY(canvas->mouseGrabberItem() == 0);
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
+ QCOMPARE(child1->releaseCount, 1);
+ child1->setVisible(true);
+
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
+ QVERIFY(canvas->mouseGrabberItem() == child1);
+ QCOMPARE(child1->pressCount, 4);
+ child2->grabMouse();
+ QVERIFY(canvas->mouseGrabberItem() == child2);
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
+ QCOMPARE(child1->releaseCount, 1);
+ QCOMPARE(child2->releaseCount, 1);
+
+ child2->grabMouse();
+ QVERIFY(canvas->mouseGrabberItem() == child2);
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
+ QCOMPARE(child1->pressCount, 4);
+ QCOMPARE(child2->pressCount, 1);
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
+ QCOMPARE(child1->releaseCount, 1);
+ QCOMPARE(child2->releaseCount, 2);
+
+ delete child1;
+ delete child2;
+ delete canvas;
+}
+
+
+QTEST_MAIN(tst_qsgitem)
+
+#include "tst_qsgitem.moc"
diff --git a/tests/auto/declarative/qsgitem2/data/childrenProperty.qml b/tests/auto/declarative/qsgitem2/data/childrenProperty.qml
new file mode 100644
index 0000000000..85ddbc1446
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/childrenProperty.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ property bool test1: root.children.length == 3
+ property bool test2: root.children[0] == item1
+ property bool test3: root.children[1] == item2
+ property bool test4: root.children[2] == item3
+ property bool test5: root.children[3] == null
+
+ children: [ Item { id: item1 }, Item { id: item2 }, Item { id: item3 } ]
+}
+
diff --git a/tests/auto/declarative/qsgitem2/data/childrenRect.qml b/tests/auto/declarative/qsgitem2/data/childrenRect.qml
new file mode 100644
index 0000000000..ebc57aefbe
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/childrenRect.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 400
+
+ property int childCount: 0;
+
+ Item {
+ objectName: "testItem"
+ width: childrenRect.width
+ height: childrenRect.height
+
+ Repeater {
+ id: repeater
+ model: childCount
+ delegate: Rectangle {
+ x: index*10
+ y: index*20
+ width: 10
+ height: 20
+
+ color: "red"
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/childrenRectBug.qml b/tests/auto/declarative/qsgitem2/data/childrenRectBug.qml
new file mode 100644
index 0000000000..86a4f19c5c
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/childrenRectBug.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 200
+
+ Item {
+ objectName: "theItem"
+ anchors.centerIn: parent
+ width: childrenRect.width
+ height: childrenRect.height
+ Rectangle {
+ id: text1
+ anchors.verticalCenter: parent.verticalCenter
+ width: 100; height: 100; color: "green"
+ }
+ Rectangle {
+ anchors.left: text1.right
+ anchors.verticalCenter: parent.verticalCenter
+ width: 100; height: 100; color: "green"
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/childrenRectBug2.qml b/tests/auto/declarative/qsgitem2/data/childrenRectBug2.qml
new file mode 100644
index 0000000000..6e80ed28af
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/childrenRectBug2.qml
@@ -0,0 +1,53 @@
+import QtQuick 2.0
+
+Rectangle {
+ width:360;
+ height: 200
+
+ Item {
+ objectName: "theItem"
+ anchors.centerIn: parent
+ width: childrenRect.width
+ height: childrenRect.height
+ Rectangle {
+ id: header1
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ width: 100; height: 50
+ color: "green"
+ }
+ Rectangle {
+ id: text1
+ anchors.top: header1.bottom
+ anchors.topMargin: 10
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: 100; height: 50
+ color: "blue"
+ }
+ }
+
+ states: [
+ State {
+ name: "row"
+ AnchorChanges {
+ target: header1
+ anchors.horizontalCenter: undefined
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.top: undefined
+ }
+ AnchorChanges {
+ target: text1
+ anchors.horizontalCenter: undefined
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.top: undefined
+ anchors.left: header1.right
+ }
+ PropertyChanges {
+ target: text1
+ anchors.leftMargin: 10
+ anchors.topMargin: 0
+ }
+ }
+ ]
+}
diff --git a/tests/auto/declarative/qsgitem2/data/childrenRectBug3.qml b/tests/auto/declarative/qsgitem2/data/childrenRectBug3.qml
new file mode 100644
index 0000000000..518e76509e
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/childrenRectBug3.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 300
+ height: 300
+
+ Rectangle {
+ height: childrenRect.height
+
+ Repeater {
+ model: 1
+ Rectangle { }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/implicitsize.qml b/tests/auto/declarative/qsgitem2/data/implicitsize.qml
new file mode 100644
index 0000000000..cc6aaf7d60
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/implicitsize.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Item {
+ implicitWidth: 200
+ implicitHeight: 100
+
+ width: 80
+ height: 60
+
+ function resetSize() {
+ width = undefined
+ height = undefined
+ }
+
+ function changeImplicit() {
+ implicitWidth = 150
+ implicitHeight = 80
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/keynavigationtest.qml b/tests/auto/declarative/qsgitem2/data/keynavigationtest.qml
new file mode 100644
index 0000000000..aacb621fb0
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/keynavigationtest.qml
@@ -0,0 +1,87 @@
+import QtQuick 2.0
+
+Grid {
+ columns: 2
+ width: 100; height: 100
+ function verify() {
+ if (item1.KeyNavigation.right != item2)
+ return false;
+ if (item1.KeyNavigation.down != item3)
+ return false;
+ if (item1.KeyNavigation.tab != item2)
+ return false;
+ if (item1.KeyNavigation.backtab != item4)
+ return false;
+
+ if (item2.KeyNavigation.left != item1)
+ return false;
+ if (item2.KeyNavigation.down != item4)
+ return false;
+ if (item2.KeyNavigation.tab != item3)
+ return false;
+ if (item2.KeyNavigation.backtab != item1)
+ return false;
+
+ if (item3.KeyNavigation.right != item4)
+ return false;
+ if (item3.KeyNavigation.up != item1)
+ return false;
+ if (item3.KeyNavigation.tab != item4)
+ return false;
+ if (item3.KeyNavigation.backtab != item2)
+ return false;
+
+ if (item4.KeyNavigation.left != item3)
+ return false;
+ if (item4.KeyNavigation.up != item2)
+ return false;
+ if (item4.KeyNavigation.tab != item1)
+ return false;
+ if (item4.KeyNavigation.backtab != item3)
+ return false;
+
+ return true;
+ }
+
+ Rectangle {
+ id: item1
+ objectName: "item1"
+ focus: true
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.right: item2
+ KeyNavigation.down: item3
+ KeyNavigation.tab: item2
+ KeyNavigation.backtab: item4
+ }
+ Rectangle {
+ id: item2
+ objectName: "item2"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.left: item1
+ KeyNavigation.down: item4
+ KeyNavigation.tab: item3
+ KeyNavigation.backtab: item1
+ }
+ Rectangle {
+ id: item3
+ objectName: "item3"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.right: item4
+ KeyNavigation.up: item1
+ KeyNavigation.tab: item4
+ KeyNavigation.backtab: item2
+ }
+ Rectangle {
+ id: item4
+ objectName: "item4"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.left: item3
+ KeyNavigation.up: item2
+ KeyNavigation.tab: item1
+ KeyNavigation.backtab: item3
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/keynavigationtest_implicit.qml b/tests/auto/declarative/qsgitem2/data/keynavigationtest_implicit.qml
new file mode 100644
index 0000000000..92d4ae23de
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/keynavigationtest_implicit.qml
@@ -0,0 +1,68 @@
+import QtQuick 2.0
+
+Grid {
+ columns: 2
+ width: 100; height: 100
+ function verify() {
+ if (item1.KeyNavigation.tab != item2)
+ return false;
+ if (item1.KeyNavigation.backtab != item4)
+ return false;
+
+ if (item2.KeyNavigation.left != item1)
+ return false;
+ if (item2.KeyNavigation.down != item4)
+ return false;
+ if (item2.KeyNavigation.tab != item3)
+ return false;
+ if (item2.KeyNavigation.backtab != item1)
+ return false;
+
+ if (item3.KeyNavigation.right != item4)
+ return false;
+ if (item3.KeyNavigation.up != item1)
+ return false;
+ if (item3.KeyNavigation.tab != item4)
+ return false;
+ if (item3.KeyNavigation.backtab != item2)
+ return false;
+
+ return true;
+ }
+
+ Rectangle {
+ id: item1
+ objectName: "item1"
+ focus: true
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.tab: item2
+ KeyNavigation.backtab: item4
+ }
+ Rectangle {
+ id: item2
+ objectName: "item2"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.left: item1
+ KeyNavigation.down: item4
+ KeyNavigation.tab: item3
+ KeyNavigation.backtab: item1
+ }
+ Rectangle {
+ id: item3
+ objectName: "item3"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ KeyNavigation.right: item4
+ KeyNavigation.up: item1
+ KeyNavigation.tab: item4
+ KeyNavigation.backtab: item2
+ }
+ Rectangle {
+ id: item4
+ objectName: "item4"
+ width: 50; height: 50
+ color: focus ? "red" : "lightgray"
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/keyspriority.qml b/tests/auto/declarative/qsgitem2/data/keyspriority.qml
new file mode 100644
index 0000000000..114cf0488a
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/keyspriority.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+import Test 1.0
+
+KeyTestItem {
+ focus: true
+ Keys.onPressed: keysTestObject.keyPress(event.key, event.text, event.modifiers)
+ Keys.onReleased: { keysTestObject.keyRelease(event.key, event.text, event.modifiers); event.accepted = true; }
+ Keys.priority: keysTestObject.processLast ? Keys.AfterItem : Keys.BeforeItem
+}
diff --git a/tests/auto/declarative/qsgitem2/data/keystest.qml b/tests/auto/declarative/qsgitem2/data/keystest.qml
new file mode 100644
index 0000000000..c70e0061f5
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/keystest.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Item {
+ focus: true
+
+ property bool isEnabled: Keys.enabled
+
+ Keys.onPressed: keysTestObject.keyPress(event.key, event.text, event.modifiers)
+ Keys.onReleased: { keysTestObject.keyRelease(event.key, event.text, event.modifiers); event.accepted = true; }
+ Keys.onReturnPressed: keysTestObject.keyPress(event.key, "Return", event.modifiers)
+ Keys.onDigit0Pressed: keysTestObject.keyPress(event.key, event.text, event.modifiers)
+ Keys.onDigit9Pressed: { event.accepted = false; keysTestObject.keyPress(event.key, event.text, event.modifiers) }
+ Keys.onTabPressed: keysTestObject.keyPress(event.key, "Tab", event.modifiers)
+ Keys.onBacktabPressed: keysTestObject.keyPress(event.key, "Backtab", event.modifiers)
+ Keys.forwardTo: [ item2 ]
+ Keys.enabled: enableKeyHanding
+
+ Item {
+ id: item2
+ visible: forwardeeVisible
+ Keys.onPressed: keysTestObject.forwardedKey(event.key)
+ Keys.onReleased: keysTestObject.forwardedKey(event.key)
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/layoutmirroring.qml b/tests/auto/declarative/qsgitem2/data/layoutmirroring.qml
new file mode 100644
index 0000000000..036819740c
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/layoutmirroring.qml
@@ -0,0 +1,54 @@
+import QtQuick 2.0
+
+Item {
+ property bool childrenInherit: true
+ Item {
+ objectName: "mirrored1"
+ LayoutMirroring.enabled: true
+ LayoutMirroring.childrenInherit: parent.childrenInherit
+ Item {
+ Item {
+ objectName: "notMirrored1"
+ LayoutMirroring.enabled: false
+ Item {
+ objectName: "inheritedMirror1"
+ }
+ }
+ Item {
+ objectName: "inheritedMirror2"
+ }
+ }
+ }
+ Item {
+ objectName: "mirrored2"
+ LayoutMirroring.enabled: true
+ LayoutMirroring.childrenInherit: false
+ Item {
+ objectName: "notMirrored2"
+ }
+ }
+ Item {
+ LayoutMirroring.enabled: true
+ LayoutMirroring.childrenInherit: true
+ Loader {
+ id: loader
+ }
+ }
+ states: State {
+ name: "newContent"
+ PropertyChanges {
+ target: loader
+ sourceComponent: component
+ }
+ }
+ Component {
+ id: component
+ Item {
+ objectName: "notMirrored3"
+ LayoutMirroring.enabled: false
+ Item {
+ objectName: "inheritedMirror3"
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/mapCoordinates.qml b/tests/auto/declarative/qsgitem2/data/mapCoordinates.qml
new file mode 100644
index 0000000000..a5a073c1a0
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/mapCoordinates.qml
@@ -0,0 +1,43 @@
+import QtQuick 2.0
+
+Item {
+ id: root; objectName: "root"
+ width: 200; height: 200
+
+ Item { id: itemA; objectName: "itemA"; x: 50; y: 50 }
+
+ Item {
+ x: 50; y: 50
+ Item { id: itemB; objectName: "itemB"; x: 100; y: 100 }
+ }
+
+ function mapAToB(x, y) {
+ var pos = itemA.mapToItem(itemB, x, y)
+ return Qt.point(pos.x, pos.y)
+ }
+
+ function mapAFromB(x, y) {
+ var pos = itemA.mapFromItem(itemB, x, y)
+ return Qt.point(pos.x, pos.y)
+ }
+
+ function mapAToNull(x, y) {
+ var pos = itemA.mapToItem(null, x, y)
+ return Qt.point(pos.x, pos.y)
+ }
+
+ function mapAFromNull(x, y) {
+ var pos = itemA.mapFromItem(null, x, y)
+ return Qt.point(pos.x, pos.y)
+ }
+
+ function checkMapAToInvalid(x, y) {
+ var pos = itemA.mapToItem(1122, x, y)
+ return pos.x == undefined && pos.y == undefined
+ }
+
+ function checkMapAFromInvalid(x, y) {
+ var pos = itemA.mapFromItem(1122, x, y)
+ return pos.x == undefined && pos.y == undefined
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/mouseFocus.qml b/tests/auto/declarative/qsgitem2/data/mouseFocus.qml
new file mode 100644
index 0000000000..b120cc0263
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/mouseFocus.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+
+QGraphicsWidget {
+ size: "200x100"
+ focusPolicy: QGraphicsWidget.ClickFocus
+ Item {
+ objectName: "declarativeItem"
+ id: item
+ width: 200
+ height: 100
+ MouseArea {
+ anchors.fill: parent
+ onPressed: {
+ if (!item.focus) {
+ item.focus = true;
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/propertychanges.qml b/tests/auto/declarative/qsgitem2/data/propertychanges.qml
new file mode 100644
index 0000000000..3fa5ea9c23
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/propertychanges.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+Item {
+ Item {
+ objectName: "item"
+ }
+ Item {
+ objectName: "parentItem"
+ }
+}
diff --git a/tests/auto/declarative/qsgitem2/data/qtbug_16871.qml b/tests/auto/declarative/qsgitem2/data/qtbug_16871.qml
new file mode 100644
index 0000000000..f1e7377730
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/qtbug_16871.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+ children: [ 10 ]
+}
diff --git a/tests/auto/declarative/qsgitem2/data/resourcesProperty.qml b/tests/auto/declarative/qsgitem2/data/resourcesProperty.qml
new file mode 100644
index 0000000000..b8f18bb375
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/resourcesProperty.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ property bool test1
+ property bool test2
+ property bool test3
+ property bool test4
+ property bool test5
+
+ Component.onCompleted: {
+ test1 = (root.resources.length >= 3)
+ test2 = root.resources[0] == item1
+ test3 = root.resources[1] == item2
+ test4 = root.resources[2] == item3
+ test5 = root.resources[10] == null
+ }
+
+ resources: [ Item { id: item1 }, Item { id: item2 }, Item { id: item3 } ]
+}
diff --git a/tests/auto/declarative/qsgitem2/data/transformCrash.qml b/tests/auto/declarative/qsgitem2/data/transformCrash.qml
new file mode 100644
index 0000000000..284e85f0e0
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/data/transformCrash.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+Item {
+ id: wrapper
+ width: 200
+ height: 200
+
+ QtObject {
+ id: object
+ }
+
+ Component.onCompleted: wrapper.transform = object
+}
diff --git a/tests/auto/declarative/qsgitem2/qsgitem.pro b/tests/auto/declarative/qsgitem2/qsgitem.pro
new file mode 100644
index 0000000000..b56eec3114
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/qsgitem.pro
@@ -0,0 +1,16 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qsgitem.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgitem2/tst_qsgitem.cpp b/tests/auto/declarative/qsgitem2/tst_qsgitem.cpp
new file mode 100644
index 0000000000..641abefa94
--- /dev/null
+++ b/tests/auto/declarative/qsgitem2/tst_qsgitem.cpp
@@ -0,0 +1,1322 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtTest/QSignalSpy>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qsgview.h>
+#include <private/qsgrectangle_p.h>
+#include <private/qsgitem_p.h>
+#include "../../../shared/util.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_QSGItem : public QObject
+
+{
+ Q_OBJECT
+public:
+ tst_QSGItem();
+
+private slots:
+ void initTestCase();
+ void keys();
+ void keysProcessingOrder();
+ void keyNavigation();
+ void keyNavigation_RightToLeft();
+ void keyNavigation_skipNotVisible();
+ void keyNavigation_implicitSetting();
+ void layoutMirroring();
+ void layoutMirroringIllegalParent();
+ void smooth();
+ void clip();
+ void mapCoordinates();
+ void mapCoordinates_data();
+ void propertyChanges();
+ void transforms();
+ void transforms_data();
+ void childrenRect();
+ void childrenRectBug();
+ void childrenRectBug2();
+ void childrenRectBug3();
+
+ void childrenProperty();
+ void resourcesProperty();
+ void mouseFocus();
+
+ void transformCrash();
+ void implicitSize();
+ void qtbug_16871();
+private:
+ QDeclarativeEngine engine;
+};
+
+template<typename T>
+T *findItem(QSGItem *parent, const QString &objectName)
+{
+ if (!parent)
+ return 0;
+
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->QSGItem::children().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
+ return static_cast<T*>(item);
+ item = findItem<T>(item, objectName);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+}
+
+class KeysTestObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool processLast READ processLast NOTIFY processLastChanged)
+
+public:
+ KeysTestObject() : mKey(0), mModifiers(0), mForwardedKey(0), mLast(false) {}
+
+ void reset() {
+ mKey = 0;
+ mText = QString();
+ mModifiers = 0;
+ mForwardedKey = 0;
+ }
+
+ bool processLast() const { return mLast; }
+ void setProcessLast(bool b) {
+ if (b != mLast) {
+ mLast = b;
+ emit processLastChanged();
+ }
+ }
+
+public slots:
+ void keyPress(int key, QString text, int modifiers) {
+ mKey = key;
+ mText = text;
+ mModifiers = modifiers;
+ }
+ void keyRelease(int key, QString text, int modifiers) {
+ mKey = key;
+ mText = text;
+ mModifiers = modifiers;
+ }
+ void forwardedKey(int key) {
+ mForwardedKey = key;
+ }
+
+signals:
+ void processLastChanged();
+
+public:
+ int mKey;
+ QString mText;
+ int mModifiers;
+ int mForwardedKey;
+ bool mLast;
+
+private:
+};
+
+class KeyTestItem : public QSGItem
+{
+ Q_OBJECT
+public:
+ KeyTestItem(QSGItem *parent=0) : QSGItem(parent), mKey(0) {}
+
+protected:
+ void keyPressEvent(QKeyEvent *e) {
+ keyPressPreHandler(e);
+ if (e->isAccepted())
+ return;
+
+ mKey = e->key();
+
+ if (e->key() == Qt::Key_A)
+ e->accept();
+ else
+ e->ignore();
+
+ if (!e->isAccepted())
+ QSGItem::keyPressEvent(e);
+ }
+
+ void keyReleaseEvent(QKeyEvent *e) {
+ keyReleasePreHandler(e);
+
+ if (e->isAccepted())
+ return;
+
+ if (e->key() == Qt::Key_B)
+ e->accept();
+ else
+ e->ignore();
+
+ if (!e->isAccepted())
+ QSGItem::keyReleaseEvent(e);
+ }
+
+public:
+ int mKey;
+};
+
+QML_DECLARE_TYPE(KeyTestItem);
+
+
+tst_QSGItem::tst_QSGItem()
+{
+}
+
+void tst_QSGItem::initTestCase()
+{
+ qmlRegisterType<KeyTestItem>("Test",1,0,"KeyTestItem");
+}
+
+void tst_QSGItem::keys()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ KeysTestObject *testObject = new KeysTestObject;
+ canvas->rootContext()->setContextProperty("keysTestObject", testObject);
+
+ canvas->rootContext()->setContextProperty("enableKeyHanding", QVariant(true));
+ canvas->rootContext()->setContextProperty("forwardeeVisible", QVariant(true));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/keystest.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QEvent wa(QEvent::WindowActivate);
+ QApplication::sendEvent(canvas, &wa);
+ QFocusEvent fe(QEvent::FocusIn);
+ QApplication::sendEvent(canvas, &fe);
+
+ QVERIFY(canvas->rootObject());
+ QCOMPARE(canvas->rootObject()->property("isEnabled").toBool(), true);
+
+ QKeyEvent key(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_A));
+ QCOMPARE(testObject->mForwardedKey, int(Qt::Key_A));
+ QCOMPARE(testObject->mText, QLatin1String("A"));
+ QVERIFY(testObject->mModifiers == Qt::NoModifier);
+ QVERIFY(!key.isAccepted());
+
+ testObject->reset();
+
+ key = QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ShiftModifier, "A", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_A));
+ QCOMPARE(testObject->mForwardedKey, int(Qt::Key_A));
+ QCOMPARE(testObject->mText, QLatin1String("A"));
+ QVERIFY(testObject->mModifiers == Qt::ShiftModifier);
+ QVERIFY(key.isAccepted());
+
+ testObject->reset();
+
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_Return));
+ QCOMPARE(testObject->mForwardedKey, int(Qt::Key_Return));
+ QCOMPARE(testObject->mText, QLatin1String("Return"));
+ QVERIFY(testObject->mModifiers == Qt::NoModifier);
+ QVERIFY(key.isAccepted());
+
+ testObject->reset();
+
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_0, Qt::NoModifier, "0", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_0));
+ QCOMPARE(testObject->mForwardedKey, int(Qt::Key_0));
+ QCOMPARE(testObject->mText, QLatin1String("0"));
+ QVERIFY(testObject->mModifiers == Qt::NoModifier);
+ QVERIFY(key.isAccepted());
+
+ testObject->reset();
+
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_9, Qt::NoModifier, "9", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_9));
+ QCOMPARE(testObject->mForwardedKey, int(Qt::Key_9));
+ QCOMPARE(testObject->mText, QLatin1String("9"));
+ QVERIFY(testObject->mModifiers == Qt::NoModifier);
+ QVERIFY(!key.isAccepted());
+
+ testObject->reset();
+
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_Tab));
+ QCOMPARE(testObject->mForwardedKey, int(Qt::Key_Tab));
+ QCOMPARE(testObject->mText, QLatin1String("Tab"));
+ QVERIFY(testObject->mModifiers == Qt::NoModifier);
+ QVERIFY(key.isAccepted());
+
+ testObject->reset();
+
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_Backtab));
+ QCOMPARE(testObject->mForwardedKey, int(Qt::Key_Backtab));
+ QCOMPARE(testObject->mText, QLatin1String("Backtab"));
+ QVERIFY(testObject->mModifiers == Qt::NoModifier);
+ QVERIFY(key.isAccepted());
+
+ testObject->reset();
+
+ canvas->rootContext()->setContextProperty("forwardeeVisible", QVariant(false));
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_A));
+ QCOMPARE(testObject->mForwardedKey, 0);
+ QCOMPARE(testObject->mText, QLatin1String("A"));
+ QVERIFY(testObject->mModifiers == Qt::NoModifier);
+ QVERIFY(!key.isAccepted());
+
+ testObject->reset();
+
+ canvas->rootContext()->setContextProperty("enableKeyHanding", QVariant(false));
+ QCOMPARE(canvas->rootObject()->property("isEnabled").toBool(), false);
+
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, 0);
+ QVERIFY(!key.isAccepted());
+
+ canvas->rootContext()->setContextProperty("enableKeyHanding", QVariant(true));
+ QCOMPARE(canvas->rootObject()->property("isEnabled").toBool(), true);
+
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_Return));
+ QVERIFY(key.isAccepted());
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QSGItem::keysProcessingOrder()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ KeysTestObject *testObject = new KeysTestObject;
+ canvas->rootContext()->setContextProperty("keysTestObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/keyspriority.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ KeyTestItem *testItem = qobject_cast<KeyTestItem*>(canvas->rootObject());
+ QVERIFY(testItem);
+
+ QEvent wa(QEvent::WindowActivate);
+ QApplication::sendEvent(canvas, &wa);
+ QFocusEvent fe(QEvent::FocusIn);
+ QApplication::sendEvent(canvas, &fe);
+
+ QKeyEvent key(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_A));
+ QCOMPARE(testObject->mText, QLatin1String("A"));
+ QVERIFY(testObject->mModifiers == Qt::NoModifier);
+ QVERIFY(key.isAccepted());
+
+ testObject->reset();
+
+ testObject->setProcessLast(true);
+
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, 0);
+ QVERIFY(key.isAccepted());
+
+ testObject->reset();
+
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_B, Qt::NoModifier, "B", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, int(Qt::Key_B));
+ QCOMPARE(testObject->mText, QLatin1String("B"));
+ QVERIFY(testObject->mModifiers == Qt::NoModifier);
+ QVERIFY(!key.isAccepted());
+
+ testObject->reset();
+
+ key = QKeyEvent(QEvent::KeyRelease, Qt::Key_B, Qt::NoModifier, "B", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QCOMPARE(testObject->mKey, 0);
+ QVERIFY(key.isAccepted());
+
+ delete canvas;
+ delete testObject;
+}
+
+QSGItemPrivate *childPrivate(QSGItem *rootItem, const char * itemString)
+{
+ QSGItem *item = findItem<QSGItem>(rootItem, QString(QLatin1String(itemString)));
+ QSGItemPrivate* itemPrivate = QSGItemPrivate::get(item);
+ return itemPrivate;
+}
+
+QVariant childProperty(QSGItem *rootItem, const char * itemString, const char * property)
+{
+ QSGItem *item = findItem<QSGItem>(rootItem, QString(QLatin1String(itemString)));
+ return item->property(property);
+}
+
+bool anchorsMirrored(QSGItem *rootItem, const char * itemString)
+{
+ QSGItem *item = findItem<QSGItem>(rootItem, QString(QLatin1String(itemString)));
+ QSGItemPrivate* itemPrivate = QSGItemPrivate::get(item);
+ return itemPrivate->anchors()->mirrored();
+}
+
+void tst_QSGItem::layoutMirroring()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/layoutmirroring.qml"));
+ canvas->show();
+
+ QSGItem *rootItem = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(rootItem);
+ QSGItemPrivate *rootPrivate = QSGItemPrivate::get(rootItem);
+ QVERIFY(rootPrivate);
+
+ QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "mirrored2")->effectiveLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false);
+ QCOMPARE(childPrivate(rootItem, "notMirrored2")->effectiveLayoutMirror, false);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, true);
+
+ QCOMPARE(anchorsMirrored(rootItem, "mirrored1"), true);
+ QCOMPARE(anchorsMirrored(rootItem, "mirrored2"), true);
+ QCOMPARE(anchorsMirrored(rootItem, "notMirrored1"), false);
+ QCOMPARE(anchorsMirrored(rootItem, "notMirrored2"), false);
+ QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror1"), true);
+ QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror2"), true);
+
+ QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritedLayoutMirror, false);
+ QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritedLayoutMirror, false);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true);
+
+ QCOMPARE(childPrivate(rootItem, "mirrored1")->isMirrorImplicit, false);
+ QCOMPARE(childPrivate(rootItem, "mirrored2")->isMirrorImplicit, false);
+ QCOMPARE(childPrivate(rootItem, "notMirrored1")->isMirrorImplicit, false);
+ QCOMPARE(childPrivate(rootItem, "notMirrored2")->isMirrorImplicit, true);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->isMirrorImplicit, true);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->isMirrorImplicit, true);
+
+ QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritMirrorFromParent, true);
+ QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritMirrorFromParent, false);
+ QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromParent, true);
+ QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritMirrorFromParent, false);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromParent, true);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromParent, true);
+
+ QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritMirrorFromItem, true);
+ QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritMirrorFromItem, false);
+ QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromItem, false);
+ QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritMirrorFromItem, false);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromItem, false);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromItem, false);
+
+ // load dynamic content using Loader that needs to inherit mirroring
+ rootItem->setProperty("state", "newContent");
+ QCOMPARE(childPrivate(rootItem, "notMirrored3")->effectiveLayoutMirror, false);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->effectiveLayoutMirror, true);
+
+ QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritedLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritedLayoutMirror, true);
+
+ QCOMPARE(childPrivate(rootItem, "notMirrored3")->isMirrorImplicit, false);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->isMirrorImplicit, true);
+
+ QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromParent, true);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritMirrorFromParent, true);
+
+ QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false);
+ QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false);
+
+ // disable inheritance
+ rootItem->setProperty("childrenInherit", false);
+
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, false);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, false);
+ QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false);
+
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, false);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, false);
+ QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, false);
+ QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, false);
+
+ // re-enable inheritance
+ rootItem->setProperty("childrenInherit", true);
+
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false);
+
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true);
+ QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true);
+
+ //
+ // dynamic parenting
+ //
+ QSGItem *parentItem1 = new QSGItem();
+ QSGItemPrivate::get(parentItem1)->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true
+ QSGItemPrivate::get(parentItem1)->isMirrorImplicit = false;
+ QSGItemPrivate::get(parentItem1)->inheritMirrorFromItem = true; // LayoutMirroring.childrenInherit: true
+ QSGItemPrivate::get(parentItem1)->resolveLayoutMirror();
+
+ // inherit in constructor
+ QSGItem *childItem1 = new QSGItem(parentItem1);
+ QCOMPARE(QSGItemPrivate::get(childItem1)->effectiveLayoutMirror, true);
+ QCOMPARE(QSGItemPrivate::get(childItem1)->inheritMirrorFromParent, true);
+
+ // inherit through a parent change
+ QSGItem *childItem2 = new QSGItem();
+ QCOMPARE(QSGItemPrivate::get(childItem2)->effectiveLayoutMirror, false);
+ QCOMPARE(QSGItemPrivate::get(childItem2)->inheritMirrorFromParent, false);
+ childItem2->setParentItem(parentItem1);
+ QCOMPARE(QSGItemPrivate::get(childItem2)->effectiveLayoutMirror, true);
+ QCOMPARE(QSGItemPrivate::get(childItem2)->inheritMirrorFromParent, true);
+
+ // stop inherting through a parent change
+ QSGItem *parentItem2 = new QSGItem();
+ QSGItemPrivate::get(parentItem2)->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true
+ QSGItemPrivate::get(parentItem2)->resolveLayoutMirror();
+ childItem2->setParentItem(parentItem2);
+ QCOMPARE(QSGItemPrivate::get(childItem2)->effectiveLayoutMirror, false);
+ QCOMPARE(QSGItemPrivate::get(childItem2)->inheritMirrorFromParent, false);
+
+ delete parentItem1;
+ delete parentItem2;
+}
+
+void tst_QSGItem::layoutMirroringIllegalParent()
+{
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 2.0; QtObject { LayoutMirroring.enabled: true; LayoutMirroring.childrenInherit: true }", QUrl::fromLocalFile(""));
+ QTest::ignoreMessage(QtWarningMsg, "file::1:21: QML QtObject: LayoutDirection attached property only works with Items");
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+}
+
+void tst_QSGItem::keyNavigation()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/keynavigationtest.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QEvent wa(QEvent::WindowActivate);
+ QApplication::sendEvent(canvas, &wa);
+ QFocusEvent fe(QEvent::FocusIn);
+ QApplication::sendEvent(canvas, &fe);
+
+ QSGItem *item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ QVariant result;
+ QVERIFY(QMetaObject::invokeMethod(canvas->rootObject(), "verify",
+ Q_RETURN_ARG(QVariant, result)));
+ QVERIFY(result.toBool());
+
+ // right
+ QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // down
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item4");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // left
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item3");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // up
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // tab
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // backtab
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ delete canvas;
+}
+
+void tst_QSGItem::keyNavigation_RightToLeft()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/keynavigationtest.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QSGItem *rootItem = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(rootItem);
+ QSGItemPrivate* rootItemPrivate = QSGItemPrivate::get(rootItem);
+
+ rootItemPrivate->effectiveLayoutMirror = true; // LayoutMirroring.mirror: true
+ rootItemPrivate->isMirrorImplicit = false;
+ rootItemPrivate->inheritMirrorFromItem = true; // LayoutMirroring.inherit: true
+ rootItemPrivate->resolveLayoutMirror();
+
+ QEvent wa(QEvent::WindowActivate);
+ QApplication::sendEvent(canvas, &wa);
+ QFocusEvent fe(QEvent::FocusIn);
+ QApplication::sendEvent(canvas, &fe);
+
+ QSGItem *item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ QVariant result;
+ QVERIFY(QMetaObject::invokeMethod(canvas->rootObject(), "verify",
+ Q_RETURN_ARG(QVariant, result)));
+ QVERIFY(result.toBool());
+
+ // right
+ QKeyEvent key(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // left
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ delete canvas;
+}
+
+void tst_QSGItem::keyNavigation_skipNotVisible()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/keynavigationtest.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QEvent wa(QEvent::WindowActivate);
+ QApplication::sendEvent(canvas, &wa);
+ QFocusEvent fe(QEvent::FocusIn);
+ QApplication::sendEvent(canvas, &fe);
+
+ QSGItem *item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Set item 2 to not visible
+ item = findItem<QSGItem>(canvas->rootObject(), "item2");
+ QVERIFY(item);
+ item->setVisible(false);
+ QVERIFY(!item->isVisible());
+
+ // right
+ QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // tab
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item3");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // backtab
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ //Set item 3 to not visible
+ item = findItem<QSGItem>(canvas->rootObject(), "item3");
+ QVERIFY(item);
+ item->setVisible(false);
+ QVERIFY(!item->isVisible());
+
+ // tab
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item4");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // backtab
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ delete canvas;
+}
+
+void tst_QSGItem::keyNavigation_implicitSetting()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/keynavigationtest_implicit.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QEvent wa(QEvent::WindowActivate);
+ QApplication::sendEvent(canvas, &wa);
+ QFocusEvent fe(QEvent::FocusIn);
+ QApplication::sendEvent(canvas, &fe);
+
+ QSGItem *item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ QVariant result;
+ QVERIFY(QMetaObject::invokeMethod(canvas->rootObject(), "verify",
+ Q_RETURN_ARG(QVariant, result)));
+ QVERIFY(result.toBool());
+
+ // right
+ QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // back to item1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // down
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item3");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // move to item4
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item4");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // left
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item3");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // back to item4
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item4");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // up
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // back to item4
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item4");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // tab
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // back to item4
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item4");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // backtab
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
+ QApplication::sendEvent(canvas, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QSGItem>(canvas->rootObject(), "item3");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ delete canvas;
+}
+
+void tst_QSGItem::smooth()
+{
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 2.0; Item { smooth: false; }", QUrl::fromLocalFile(""));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QSignalSpy spy(item, SIGNAL(smoothChanged(bool)));
+
+ QVERIFY(item);
+ QVERIFY(!item->smooth());
+
+ item->setSmooth(true);
+ QVERIFY(item->smooth());
+ QCOMPARE(spy.count(),1);
+ QList<QVariant> arguments = spy.first();
+ QVERIFY(arguments.count() == 1);
+ QVERIFY(arguments.at(0).toBool() == true);
+
+ item->setSmooth(true);
+ QCOMPARE(spy.count(),1);
+
+ item->setSmooth(false);
+ QVERIFY(!item->smooth());
+ QCOMPARE(spy.count(),2);
+ item->setSmooth(false);
+ QCOMPARE(spy.count(),2);
+
+ delete item;
+}
+
+void tst_QSGItem::clip()
+{
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 2.0\nItem { clip: false\n }", QUrl::fromLocalFile(""));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QSignalSpy spy(item, SIGNAL(clipChanged(bool)));
+
+ QVERIFY(item);
+ QVERIFY(!item->clip());
+
+ item->setClip(true);
+ QVERIFY(item->clip());
+
+ QList<QVariant> arguments = spy.first();
+ QVERIFY(arguments.count() == 1);
+ QVERIFY(arguments.at(0).toBool() == true);
+
+ QCOMPARE(spy.count(),1);
+ item->setClip(true);
+ QCOMPARE(spy.count(),1);
+
+ item->setClip(false);
+ QVERIFY(!item->clip());
+ QCOMPARE(spy.count(),2);
+ item->setClip(false);
+ QCOMPARE(spy.count(),2);
+
+ delete item;
+}
+
+void tst_QSGItem::mapCoordinates()
+{
+ QFETCH(int, x);
+ QFETCH(int, y);
+
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(300, 300);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/mapCoordinates.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QSGItem *root = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(root != 0);
+ QSGItem *a = findItem<QSGItem>(canvas->rootObject(), "itemA");
+ QVERIFY(a != 0);
+ QSGItem *b = findItem<QSGItem>(canvas->rootObject(), "itemB");
+ QVERIFY(b != 0);
+
+ QVariant result;
+
+ QVERIFY(QMetaObject::invokeMethod(root, "mapAToB",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
+ QCOMPARE(result.value<QPointF>(), qobject_cast<QSGItem*>(a)->mapToItem(b, QPointF(x, y)));
+
+ QVERIFY(QMetaObject::invokeMethod(root, "mapAFromB",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
+ QCOMPARE(result.value<QPointF>(), qobject_cast<QSGItem*>(a)->mapFromItem(b, QPointF(x, y)));
+
+ QVERIFY(QMetaObject::invokeMethod(root, "mapAToNull",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
+ QCOMPARE(result.value<QPointF>(), qobject_cast<QSGItem*>(a)->mapToScene(QPointF(x, y)));
+
+ QVERIFY(QMetaObject::invokeMethod(root, "mapAFromNull",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
+ QCOMPARE(result.value<QPointF>(), qobject_cast<QSGItem*>(a)->mapFromScene(QPointF(x, y)));
+
+ QString warning1 = QUrl::fromLocalFile(SRCDIR "/data/mapCoordinates.qml").toString() + ":7:5: QML Item: mapToItem() given argument \"1122\" which is neither null nor an Item";
+ QString warning2 = QUrl::fromLocalFile(SRCDIR "/data/mapCoordinates.qml").toString() + ":7:5: QML Item: mapFromItem() given argument \"1122\" which is neither null nor an Item";
+
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+ QVERIFY(QMetaObject::invokeMethod(root, "checkMapAToInvalid",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
+ QVERIFY(result.toBool());
+
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+ QVERIFY(QMetaObject::invokeMethod(root, "checkMapAFromInvalid",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
+ QVERIFY(result.toBool());
+
+ delete canvas;
+}
+
+void tst_QSGItem::mapCoordinates_data()
+{
+ QTest::addColumn<int>("x");
+ QTest::addColumn<int>("y");
+
+ for (int i=-20; i<=20; i+=10)
+ QTest::newRow(QTest::toString(i)) << i << i;
+}
+
+void tst_QSGItem::transforms_data()
+{
+ QTest::addColumn<QByteArray>("qml");
+ QTest::addColumn<QMatrix>("matrix");
+ QTest::newRow("translate") << QByteArray("Translate { x: 10; y: 20 }")
+ << QMatrix(1,0,0,1,10,20);
+ QTest::newRow("rotation") << QByteArray("Rotation { angle: 90 }")
+ << QMatrix(0,1,-1,0,0,0);
+ QTest::newRow("scale") << QByteArray("Scale { xScale: 1.5; yScale: -2 }")
+ << QMatrix(1.5,0,0,-2,0,0);
+ QTest::newRow("sequence") << QByteArray("[ Translate { x: 10; y: 20 }, Scale { xScale: 1.5; yScale: -2 } ]")
+ << QMatrix(1,0,0,1,10,20) * QMatrix(1.5,0,0,-2,0,0);
+}
+
+void tst_QSGItem::transforms()
+{
+ QFAIL("This test has not been ported yet");
+ /*QFETCH(QByteArray, qml);
+ QFETCH(QMatrix, matrix);
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 2.0\nItem { transform: "+qml+"}", QUrl::fromLocalFile(""));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QCOMPARE(item->sceneMatrix(), matrix);*/
+}
+
+void tst_QSGItem::childrenProperty()
+{
+ QDeclarativeComponent component(&engine, SRCDIR "/data/childrenProperty.qml");
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ QCOMPARE(o->property("test3").toBool(), true);
+ QCOMPARE(o->property("test4").toBool(), true);
+ QCOMPARE(o->property("test5").toBool(), true);
+ delete o;
+}
+
+void tst_QSGItem::resourcesProperty()
+{
+ QDeclarativeComponent component(&engine, SRCDIR "/data/resourcesProperty.qml");
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ QCOMPARE(o->property("test3").toBool(), true);
+ QCOMPARE(o->property("test4").toBool(), true);
+ QCOMPARE(o->property("test5").toBool(), true);
+ delete o;
+}
+
+void tst_QSGItem::mouseFocus()
+{
+ QSGView *canvas = new QSGView(0);
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/mouseFocus.qml"));
+ canvas->show();
+ QVERIFY(canvas->rootObject());
+ QApplication::setActiveWindow(canvas);
+ QTest::qWaitForWindowShown(canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
+
+ QSGItem *item = findItem<QSGItem>(canvas->rootObject(), "declarativeItem");
+ QVERIFY(item);
+ QSignalSpy focusSpy(item, SIGNAL(activeFocusChanged(bool)));
+
+ QTest::mouseClick(canvas, Qt::LeftButton, 0, item->mapToScene(QPointF(0,0)).toPoint());
+ QApplication::processEvents();
+ QCOMPARE(focusSpy.count(), 1);
+ QVERIFY(item->hasActiveFocus());
+
+ // make sure focusable graphics widget underneath does not steal focus
+ QTest::mouseClick(canvas, Qt::LeftButton, 0, item->mapToScene(QPointF(0,0)).toPoint());
+ QApplication::processEvents();
+ QCOMPARE(focusSpy.count(), 1);
+ QVERIFY(item->hasActiveFocus());
+
+ item->setFocus(false);
+ QVERIFY(!item->hasActiveFocus());
+ QCOMPARE(focusSpy.count(), 2);
+ item->setFocus(true);
+ QCOMPARE(focusSpy.count(), 3);
+
+ delete canvas;
+}
+
+void tst_QSGItem::propertyChanges()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
+ canvas->show();
+
+ QEvent wa(QEvent::WindowActivate);
+ QApplication::sendEvent(canvas, &wa);
+ QFocusEvent fe(QEvent::FocusIn);
+ QApplication::sendEvent(canvas, &fe);
+
+ QSGItem *item = findItem<QSGItem>(canvas->rootObject(), "item");
+ QSGItem *parentItem = findItem<QSGItem>(canvas->rootObject(), "parentItem");
+
+ QVERIFY(item);
+ QVERIFY(parentItem);
+
+ QSignalSpy parentSpy(item, SIGNAL(parentChanged(QSGItem *)));
+ QSignalSpy widthSpy(item, SIGNAL(widthChanged()));
+ QSignalSpy heightSpy(item, SIGNAL(heightChanged()));
+ QSignalSpy baselineOffsetSpy(item, SIGNAL(baselineOffsetChanged(qreal)));
+ QSignalSpy childrenRectSpy(parentItem, SIGNAL(childrenRectChanged(QRectF)));
+ QSignalSpy focusSpy(item, SIGNAL(focusChanged(bool)));
+ QSignalSpy wantsFocusSpy(parentItem, SIGNAL(activeFocusChanged(bool)));
+ QSignalSpy childrenChangedSpy(parentItem, SIGNAL(childrenChanged()));
+ QSignalSpy xSpy(item, SIGNAL(xChanged()));
+ QSignalSpy ySpy(item, SIGNAL(yChanged()));
+
+ item->setParentItem(parentItem);
+ item->setWidth(100.0);
+ item->setHeight(200.0);
+ item->setFocus(true);
+ item->setBaselineOffset(10.0);
+
+ QCOMPARE(item->parentItem(), parentItem);
+ QCOMPARE(parentSpy.count(),1);
+ QList<QVariant> parentArguments = parentSpy.first();
+ QVERIFY(parentArguments.count() == 1);
+ QCOMPARE(item->parentItem(), qvariant_cast<QSGItem *>(parentArguments.at(0)));
+ QCOMPARE(childrenChangedSpy.count(),1);
+
+ item->setParentItem(parentItem);
+ QCOMPARE(childrenChangedSpy.count(),1);
+
+ QCOMPARE(item->width(), 100.0);
+ QCOMPARE(widthSpy.count(),1);
+
+ QCOMPARE(item->height(), 200.0);
+ QCOMPARE(heightSpy.count(),1);
+
+ QCOMPARE(item->baselineOffset(), 10.0);
+ QCOMPARE(baselineOffsetSpy.count(),1);
+ QList<QVariant> baselineOffsetArguments = baselineOffsetSpy.first();
+ QVERIFY(baselineOffsetArguments.count() == 1);
+ QCOMPARE(item->baselineOffset(), baselineOffsetArguments.at(0).toReal());
+
+ QCOMPARE(parentItem->childrenRect(), QRectF(0.0,0.0,100.0,200.0));
+ QCOMPARE(childrenRectSpy.count(),2);
+ QList<QVariant> childrenRectArguments = childrenRectSpy.at(1);
+ QVERIFY(childrenRectArguments.count() == 1);
+ QCOMPARE(parentItem->childrenRect(), childrenRectArguments.at(0).toRectF());
+
+ QCOMPARE(item->hasActiveFocus(), true);
+ QCOMPARE(focusSpy.count(),1);
+ QList<QVariant> focusArguments = focusSpy.first();
+ QVERIFY(focusArguments.count() == 1);
+ QCOMPARE(focusArguments.at(0).toBool(), true);
+
+ QCOMPARE(parentItem->hasActiveFocus(), false);
+ QCOMPARE(parentItem->hasFocus(), false);
+ QCOMPARE(wantsFocusSpy.count(),0);
+
+ item->setX(10.0);
+ QCOMPARE(item->x(), 10.0);
+ QCOMPARE(xSpy.count(), 1);
+
+ item->setY(10.0);
+ QCOMPARE(item->y(), 10.0);
+ QCOMPARE(ySpy.count(), 1);
+
+ delete canvas;
+}
+
+void tst_QSGItem::childrenRect()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/childrenRect.qml"));
+ canvas->show();
+
+ QSGItem *o = canvas->rootObject();
+ QSGItem *item = o->findChild<QSGItem*>("testItem");
+ QCOMPARE(item->width(), qreal(0));
+ QCOMPARE(item->height(), qreal(0));
+
+ o->setProperty("childCount", 1);
+ QCOMPARE(item->width(), qreal(10));
+ QCOMPARE(item->height(), qreal(20));
+
+ o->setProperty("childCount", 5);
+ QCOMPARE(item->width(), qreal(50));
+ QCOMPARE(item->height(), qreal(100));
+
+ o->setProperty("childCount", 0);
+ QCOMPARE(item->width(), qreal(0));
+ QCOMPARE(item->height(), qreal(0));
+
+ delete o;
+ delete canvas;
+}
+
+// QTBUG-11383
+void tst_QSGItem::childrenRectBug()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/childrenRectBug.qml"));
+ canvas->show();
+
+ QSGItem *o = canvas->rootObject();
+ QSGItem *item = o->findChild<QSGItem*>("theItem");
+ QCOMPARE(item->width(), qreal(200));
+ QCOMPARE(item->height(), qreal(100));
+ QCOMPARE(item->x(), qreal(100));
+
+ delete canvas;
+}
+
+// QTBUG-11465
+void tst_QSGItem::childrenRectBug2()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/childrenRectBug2.qml"));
+ canvas->show();
+
+ QSGRectangle *rect = qobject_cast<QSGRectangle*>(canvas->rootObject());
+ QVERIFY(rect);
+ QSGItem *item = rect->findChild<QSGItem*>("theItem");
+ QCOMPARE(item->width(), qreal(100));
+ QCOMPARE(item->height(), qreal(110));
+ QCOMPARE(item->x(), qreal(130));
+
+ QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
+ rectPrivate->setState("row");
+ QCOMPARE(item->width(), qreal(210));
+ QCOMPARE(item->height(), qreal(50));
+ QCOMPARE(item->x(), qreal(75));
+
+ delete canvas;
+}
+
+// QTBUG-12722
+void tst_QSGItem::childrenRectBug3()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/childrenRectBug3.qml"));
+ canvas->show();
+
+ //don't crash on delete
+ delete canvas;
+}
+
+// QTBUG-13893
+void tst_QSGItem::transformCrash()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/transformCrash.qml"));
+ canvas->show();
+
+ delete canvas;
+}
+
+void tst_QSGItem::implicitSize()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/implicitsize.qml"));
+ canvas->show();
+
+ QSGItem *item = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(item);
+ QCOMPARE(item->width(), qreal(80));
+ QCOMPARE(item->height(), qreal(60));
+
+ QCOMPARE(item->implicitWidth(), qreal(200));
+ QCOMPARE(item->implicitHeight(), qreal(100));
+
+ QMetaObject::invokeMethod(item, "resetSize");
+
+ QCOMPARE(item->width(), qreal(200));
+ QCOMPARE(item->height(), qreal(100));
+
+ QMetaObject::invokeMethod(item, "changeImplicit");
+
+ QCOMPARE(item->implicitWidth(), qreal(150));
+ QCOMPARE(item->implicitHeight(), qreal(80));
+ QCOMPARE(item->width(), qreal(150));
+ QCOMPARE(item->height(), qreal(80));
+
+ delete canvas;
+}
+
+void tst_QSGItem::qtbug_16871()
+{
+ QDeclarativeComponent component(&engine, SRCDIR "/data/qtbug_16871.qml");
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ delete o;
+}
+
+QTEST_MAIN(tst_QSGItem)
+
+#include "tst_qsgitem.moc"
diff --git a/tests/auto/declarative/qsglistview/data/attachedSignals.qml b/tests/auto/declarative/qsglistview/data/attachedSignals.qml
new file mode 100644
index 0000000000..2c3c0bbada
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/attachedSignals.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+ListView {
+ id: view
+ width: 240; height: 320
+
+ property variant addedDelegates: []
+ property int removedDelegateCount
+
+ model: testModel
+
+ delegate: Rectangle {
+ width: 200; height: delegateHeight
+ border.width: 1
+ ListView.onAdd: {
+ var obj = ListView.view.addedDelegates
+ obj.push(model.name)
+ ListView.view.addedDelegates = obj
+ }
+ ListView.onRemove: {
+ view.removedDelegateCount += 1
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/displaylist.qml b/tests/auto/declarative/qsglistview/data/displaylist.qml
new file mode 100644
index 0000000000..c083da5aa5
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/displaylist.qml
@@ -0,0 +1,50 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ property real delegateHeight: 20
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: root.delegateHeight
+ Behavior on height { NumberAnimation {} }
+ width: 240
+ Text {
+ text: index
+ }
+ Text {
+ x: 30
+ objectName: "displayText"
+ text: display
+ }
+ Text {
+ x: 200
+ text: wrapper.y
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ },
+ Component {
+ id: myHighlight
+ Rectangle { color: "green" }
+ }
+ ]
+ ListView {
+ id: list
+ objectName: "list"
+ focus: true
+ width: 240
+ height: 320
+ model: testModel
+ delegate: myDelegate
+ highlight: myHighlight
+ highlightMoveSpeed: 1000
+ highlightResizeSpeed: 1000
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/footer.qml b/tests/auto/declarative/qsglistview/data/footer.qml
new file mode 100644
index 0000000000..49e1944b6a
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/footer.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.0
+
+Rectangle {
+ function changeFooter() {
+ list.footer = footer2
+ }
+ width: 240
+ height: 320
+ color: "#ffffff"
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 240
+ Text {
+ text: index
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ ListView {
+ id: list
+ objectName: "list"
+ focus: true
+ width: 240
+ height: 320
+ model: testModel
+ delegate: myDelegate
+ footer: Text { objectName: "footer"; text: "Footer"; height: 30 }
+ }
+
+ Component {
+ id: footer2
+ Text { objectName: "footer2"; text: "Footer 2"; height: 20 }
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/header.qml b/tests/auto/declarative/qsglistview/data/header.qml
new file mode 100644
index 0000000000..455159f39d
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/header.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.0
+
+Rectangle {
+ function changeHeader() {
+ list.header = header2
+ }
+ width: 240
+ height: 320
+ color: "#ffffff"
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 30
+ width: 240
+ Text {
+ text: index
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ ListView {
+ id: list
+ objectName: "list"
+ focus: true
+ width: 240
+ height: 320
+ snapMode: ListView.SnapToItem
+ model: testModel
+ delegate: myDelegate
+ header: Text { objectName: "header"; text: "Header"; height: 20 }
+ }
+ Component {
+ id: header2
+ Text { objectName: "header2"; text: "Header 2"; height: 10 }
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/header1.qml b/tests/auto/declarative/qsglistview/data/header1.qml
new file mode 100644
index 0000000000..8ba6e57594
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/header1.qml
@@ -0,0 +1,33 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+
+ ListModel { id: testModel }
+
+ ListView {
+ id: list
+ objectName: "list"
+ width: parent.width
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ model: testModel
+ delegate: Text {
+ objectName: "wrapper"
+ font.pointSize: 20
+ text: index
+ }
+ footer: Rectangle {
+ width: parent.width
+ height: 40
+ color: "green"
+ }
+ header: Text { objectName: "header"; text: "Header" }
+ }
+
+ Component.onCompleted: {
+ for (var i=0; i<30; i++) testModel.append({"name" : i, "val": i})
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/headerfooter.qml b/tests/auto/declarative/qsglistview/data/headerfooter.qml
new file mode 100644
index 0000000000..30b7199445
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/headerfooter.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+
+ListView {
+ id: view
+ property bool horizontal: false
+ property bool rtl: false
+ width: 240
+ height: 320
+
+ orientation: horizontal ? ListView.Horizontal : ListView.Vertical
+ header: Rectangle {
+ objectName: "header"
+ width: horizontal ? 20 : view.width
+ height: horizontal ? view.height : 20
+ color: "red"
+ }
+ footer: Rectangle {
+ objectName: "footer"
+ width: horizontal ? 30 : view.width
+ height: horizontal ? view.height : 30
+ color: "blue"
+ }
+// model: testModel
+ delegate: Text { width: 30; height: 30; text: index + "(" + x + ")" }
+ layoutDirection: rtl ? Qt.RightToLeft : Qt.LeftToRight
+}
diff --git a/tests/auto/declarative/qsglistview/data/itemlist.qml b/tests/auto/declarative/qsglistview/data/itemlist.qml
new file mode 100644
index 0000000000..90dd59795b
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/itemlist.qml
@@ -0,0 +1,43 @@
+// This example demonstrates placing items in a view using
+// a VisualItemModel
+
+import QtQuick 2.0
+
+Rectangle {
+ color: "lightgray"
+ width: 240
+ height: 320
+
+ VisualItemModel {
+ id: itemModel
+ objectName: "itemModel"
+ Rectangle {
+ objectName: "item1"
+ height: ListView.view.height; width: view.width; color: "#FFFEF0"
+ Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ Rectangle {
+ objectName: "item2"
+ height: ListView.view.height; width: view.width; color: "#F0FFF7"
+ Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ Rectangle {
+ objectName: "item3"
+ height: ListView.view.height; width: view.width; color: "#F4F0FF"
+ Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ }
+
+ ListView {
+ id: view
+ objectName: "view"
+ anchors.fill: parent
+ anchors.bottomMargin: 30
+ model: itemModel
+ preferredHighlightBegin: 0
+ preferredHighlightEnd: 0
+ highlightRangeMode: "StrictlyEnforceRange"
+ orientation: ListView.Horizontal
+ flickDeceleration: 2000
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/listview-enforcerange.qml b/tests/auto/declarative/qsglistview/data/listview-enforcerange.qml
new file mode 100644
index 0000000000..f1bf6c2b57
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/listview-enforcerange.qml
@@ -0,0 +1,55 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+ Component {
+ id: myDelegate
+ Item {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 240
+ Text {
+ text: index
+ }
+ Text {
+ x: 30
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ x: 120
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ Text {
+ x: 200
+ text: wrapper.y
+ }
+ }
+ }
+
+ Component {
+ id: myHighlight
+ Rectangle {
+ color: "lightsteelblue"
+ }
+ }
+
+ ListView {
+ id: list
+ objectName: "list"
+ width: 240
+ height: 320
+ model: testModel
+ delegate: myDelegate
+ highlight: myHighlight
+ preferredHighlightBegin: 100
+ preferredHighlightEnd: 100
+ highlightRangeMode: "StrictlyEnforceRange"
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/listview-initCurrent.qml b/tests/auto/declarative/qsglistview/data/listview-initCurrent.qml
new file mode 100644
index 0000000000..ee1a333de0
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/listview-initCurrent.qml
@@ -0,0 +1,51 @@
+import QtQuick 2.0
+
+Rectangle {
+ property int current: list.currentIndex
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 240
+ Text {
+ text: index
+ }
+ Text {
+ x: 30
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ x: 120
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ Text {
+ x: 200
+ text: wrapper.y
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ ]
+ ListView {
+ id: list
+ objectName: "list"
+ focus: true
+ currentIndex: 20
+ width: 240
+ height: 320
+ keyNavigationWraps: testWrap
+ delegate: myDelegate
+ highlightMoveSpeed: 1000
+ model: testModel
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/listview-noCurrent.qml b/tests/auto/declarative/qsglistview/data/listview-noCurrent.qml
new file mode 100644
index 0000000000..079966d8e4
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/listview-noCurrent.qml
@@ -0,0 +1,50 @@
+import QtQuick 2.0
+
+Rectangle {
+ property int current: list.currentIndex
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 240
+ Text {
+ text: index
+ }
+ Text {
+ x: 30
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ x: 120
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ Text {
+ x: 200
+ text: wrapper.y
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ ]
+ ListView {
+ id: list
+ objectName: "list"
+ focus: true
+ currentIndex: -1
+ width: 240
+ height: 320
+ delegate: myDelegate
+ highlightMoveSpeed: 1000
+ model: testModel
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/listview-sections.qml b/tests/auto/declarative/qsglistview/data/listview-sections.qml
new file mode 100644
index 0000000000..d5b8a4400d
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/listview-sections.qml
@@ -0,0 +1,64 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: myDelegate
+ Item {
+ id: wrapper
+ objectName: "wrapper"
+ height: ListView.previousSection != ListView.section ? 40 : 20;
+ width: 240
+ Rectangle {
+ y: wrapper.ListView.previousSection != wrapper.ListView.section ? 20 : 0
+ 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
+ }
+ }
+ Rectangle {
+ color: "#99bb99"
+ height: wrapper.ListView.previousSection != wrapper.ListView.section ? 20 : 0
+ width: parent.width
+ visible: wrapper.ListView.previousSection != wrapper.ListView.section ? true : false
+ Text { text: wrapper.ListView.section }
+ }
+ }
+ }
+ ]
+ ListView {
+ id: list
+ objectName: "list"
+ width: 240
+ height: 320
+ model: testModel
+ delegate: myDelegate
+ section.property: "number"
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/listview-sections_delegate.qml b/tests/auto/declarative/qsglistview/data/listview-sections_delegate.qml
new file mode 100644
index 0000000000..82f332c951
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/listview-sections_delegate.qml
@@ -0,0 +1,69 @@
+import QtQuick 2.0
+
+Rectangle {
+ property string sectionProperty: "number"
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: myDelegate
+ Item {
+ id: wrapper
+ objectName: "wrapper"
+ 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
+ model: testModel
+ delegate: myDelegate
+ section.property: sectionProperty
+ section.delegate: Rectangle {
+ objectName: "sect_" + section
+ color: "#99bb99"
+ height: 20
+ width: list.width
+ Text { text: section }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/listviewtest.qml b/tests/auto/declarative/qsglistview/data/listviewtest.qml
new file mode 100644
index 0000000000..832eaafa0f
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/listviewtest.qml
@@ -0,0 +1,132 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width: 240
+ height: 320
+ color: "#ffffff"
+
+ property bool showHeader: false
+ property bool showFooter: false
+ property real hr: list.visibleArea.heightRatio
+ function heightRatio() {
+ return list.visibleArea.heightRatio
+ }
+
+ function checkProperties() {
+ testObject.error = false;
+ if (list.model != testModel) {
+ console.log("model property incorrect");
+ testObject.error = true;
+ }
+ if (!testObject.animate && list.delegate != myDelegate) {
+ console.log("delegate property incorrect - expected myDelegate");
+ testObject.error = true;
+ }
+ if (testObject.animate && list.delegate != animatedDelegate) {
+ console.log("delegate property incorrect - expected animatedDelegate");
+ testObject.error = true;
+ }
+ if (testObject.invalidHighlight && list.highlight != invalidHl) {
+ console.log("highlight property incorrect - expected invalidHl");
+ testObject.error = true;
+ }
+ if (!testObject.invalidHighlight && list.highlight != myHighlight) {
+ console.log("highlight property incorrect - expected myHighlight");
+ testObject.error = true;
+ }
+ }
+ resources: [
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 240
+ Text {
+ text: index
+ }
+ Text {
+ x: 30
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ x: 120
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ Text {
+ x: 200
+ text: wrapper.y
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ },
+ Component {
+ id: animatedDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 240
+ Text {
+ text: index
+ }
+ Text {
+ x: 30
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ x: 120
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ Text {
+ x: 200
+ text: wrapper.y
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ ListView.onRemove: SequentialAnimation {
+ PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true }
+ NumberAnimation { target: wrapper; property: "scale"; to: 0; duration: 250; easing.type: "InOutQuad" }
+ PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
+
+ }
+ }
+ },
+ Component {
+ id: myHighlight
+ Rectangle { color: "green" }
+ },
+ Component {
+ id: invalidHl
+ SmoothedAnimation {}
+ },
+ Component {
+ id: headerFooter
+ Rectangle { height: 30; width: 240; color: "blue" }
+ }
+ ]
+ ListView {
+ id: list
+ objectName: "list"
+ focus: true
+ width: 240
+ height: 320
+ model: testModel
+ delegate: testObject.animate ? animatedDelegate : myDelegate
+ highlight: testObject.invalidHighlight ? invalidHl : myHighlight
+ highlightMoveSpeed: 1000
+ highlightResizeSpeed: 1000
+ cacheBuffer: testObject.cacheBuffer
+ header: root.showHeader ? headerFooter : null
+ footer: root.showFooter ? headerFooter : null
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/manual-highlight.qml b/tests/auto/declarative/qsglistview/data/manual-highlight.qml
new file mode 100644
index 0000000000..aac4599f01
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/manual-highlight.qml
@@ -0,0 +1,47 @@
+import QtQuick 2.0
+
+Item {
+
+ ListModel {
+ id: model
+ ListElement {
+ name: "Bill Smith"
+ number: "555 3264"
+ }
+ ListElement {
+ name: "John Brown"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Sam Wise"
+ number: "555 0473"
+ }
+ ListElement {
+ name: "Bob Brown"
+ number: "555 5845"
+ }
+ }
+
+ Component {
+ id: highlight
+ Rectangle {
+ objectName: "highlight"
+ width: 180; height: 20
+ color: "lightsteelblue"; radius: 5
+ y: list.currentItem.y+5
+ }
+ }
+
+ ListView {
+ id: list
+ objectName: "list"
+ anchors.fill: parent
+ model: model
+ delegate: Text { objectName: "wrapper"; text: name }
+
+ highlight: highlight
+ highlightFollowsCurrentItem: false
+ focus: true
+ }
+
+}
diff --git a/tests/auto/declarative/qsglistview/data/propertychangestest.qml b/tests/auto/declarative/qsglistview/data/propertychangestest.qml
new file mode 100644
index 0000000000..146f3f13b0
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/propertychangestest.qml
@@ -0,0 +1,71 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 180; height: 120; color: "white"
+ Component {
+ id: delegate
+ Item {
+ id: wrapper
+ width: 180; height: 40;
+ Column {
+ x: 5; y: 5
+ Text { text: '<b>Name:</b> ' + name }
+ Text { text: '<b>Number:</b> ' + number }
+ }
+ }
+ }
+ Component {
+ id: highlightRed
+ Rectangle {
+ color: "red"
+ radius: 10
+ opacity: 0.5
+ }
+ }
+ ListView {
+ objectName: "listView"
+ anchors.fill: parent
+ model: listModel
+ delegate: delegate
+ highlight: highlightRed
+ focus: true
+ highlightFollowsCurrentItem: true
+ preferredHighlightBegin: 0.0
+ preferredHighlightEnd: 0.0
+ highlightRangeMode: ListView.ApplyRange
+ keyNavigationWraps: true
+ cacheBuffer: 10
+ snapMode: ListView.SnapToItem
+ }
+
+ data:[
+ ListModel {
+ id: listModel
+ ListElement {
+ name: "Bill Smith"
+ number: "555 3264"
+ }
+ ListElement {
+ name: "John Brown"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Sam Wise"
+ number: "555 0473"
+ }
+ },
+ ListModel {
+ objectName: "alternateModel"
+ ListElement {
+ name: "Jack"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Mary"
+ number: "555 3264"
+ }
+ }
+ ]
+}
+
+
diff --git a/tests/auto/declarative/qsglistview/data/qtbug14821.qml b/tests/auto/declarative/qsglistview/data/qtbug14821.qml
new file mode 100644
index 0000000000..0a5e0acbb4
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/qtbug14821.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.0
+
+ListView {
+ id: view
+ width: 300; height: 200
+ focus: true
+ keyNavigationWraps: true
+
+ model: 100
+
+ preferredHighlightBegin: 90
+ preferredHighlightEnd: 110
+
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ highlight: Component {
+ Rectangle {
+ border.color: "blue"
+ border.width: 3
+ color: "transparent"
+ width: 300; height: 15
+ }
+ }
+
+ delegate: Component {
+ Item {
+ height: 15 + (view.currentIndex == index ? 20 : 0)
+ width: 200
+ Text { text: 'Index: ' + index; anchors.verticalCenter: parent.verticalCenter }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/qtbug16037.qml b/tests/auto/declarative/qsglistview/data/qtbug16037.qml
new file mode 100644
index 0000000000..21faeb3f32
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/qtbug16037.qml
@@ -0,0 +1,37 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+
+ function setModel() {
+ listView.model = listModel1
+ }
+
+ ListModel {
+ id: listModel1
+ ListElement { text: "Apple" }
+ ListElement { text: "Banana" }
+ ListElement { text: "Orange" }
+ ListElement { text: "Coconut" }
+ }
+
+ Rectangle {
+ width: 200
+ height: listView.contentHeight
+ color: "yellow"
+ anchors.centerIn: parent
+
+ ListView {
+ id: listView
+ objectName: "listview"
+ anchors.fill: parent
+
+ delegate: Item {
+ width: 200
+ height: 20
+ Text { text: model.text; anchors.centerIn: parent }
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/rightToLeft.qml b/tests/auto/declarative/qsglistview/data/rightToLeft.qml
new file mode 100644
index 0000000000..6d77de26f4
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/rightToLeft.qml
@@ -0,0 +1,42 @@
+// This example demonstrates how item positioning
+// changes in right-to-left layout direction
+
+import QtQuick 2.0
+
+Rectangle {
+ color: "lightgray"
+ width: 640
+ height: 320
+
+ VisualItemModel {
+ id: itemModel
+ objectName: "itemModel"
+ Rectangle {
+ objectName: "item1"
+ height: view.height; width: 100; color: "#FFFEF0"
+ Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ Rectangle {
+ objectName: "item2"
+ height: view.height; width: 200; color: "#F0FFF7"
+ Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ Rectangle {
+ objectName: "item3"
+ height: view.height; width: 240; color: "#F4F0FF"
+ Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ }
+
+ ListView {
+ id: view
+ objectName: "view"
+ anchors.fill: parent
+ anchors.bottomMargin: 30
+ model: itemModel
+ highlightRangeMode: "StrictlyEnforceRange"
+ orientation: ListView.Horizontal
+ flickDeceleration: 2000
+ layoutDirection: Qt.RightToLeft
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/sizelessthan1.qml b/tests/auto/declarative/qsglistview/data/sizelessthan1.qml
new file mode 100644
index 0000000000..aa9dc20ae9
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/sizelessthan1.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 0.5
+ width: 240
+ color: ((index % 2) == 1 ? "red" : "blue")
+ }
+ }
+ ListView {
+ id: list
+ objectName: "list"
+ focus: true
+ width: 240
+ height: 320
+ model: testModel
+ delegate: myDelegate
+ }
+}
diff --git a/tests/auto/declarative/qsglistview/data/strictlyenforcerange.qml b/tests/auto/declarative/qsglistview/data/strictlyenforcerange.qml
new file mode 100644
index 0000000000..7960ac4abb
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/data/strictlyenforcerange.qml
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+
+ListView {
+ id: list
+ objectName: "list"
+ width: 320
+ height: 480
+
+ function fillModel() {
+ list.model.append({"col": "red"});
+ list.currentIndex = list.count-1
+ list.model.append({"col": "blue"});
+ list.currentIndex = list.count-1
+ list.model.append({"col": "green"});
+ list.currentIndex = list.count-1
+ }
+
+ model: ListModel { id: listModel } // empty model
+ delegate: Rectangle { id: wrapper; objectName: "wrapper"; color: col; width: 300; height: 400 }
+ orientation: "Horizontal"
+ snapMode: "SnapToItem"
+ cacheBuffer: 1000
+
+ preferredHighlightBegin: 10
+ preferredHighlightEnd: 10
+
+ highlightRangeMode: "StrictlyEnforceRange"
+ focus: true
+}
diff --git a/tests/auto/declarative/qsglistview/incrementalmodel.cpp b/tests/auto/declarative/qsglistview/incrementalmodel.cpp
new file mode 100644
index 0000000000..cd0512fb06
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/incrementalmodel.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "incrementalmodel.h"
+#include <QApplication>
+#include <QDebug>
+
+IncrementalModel::IncrementalModel(QObject *parent)
+ : QAbstractListModel(parent), count(0)
+{
+ for (int i = 0; i < 100; ++i)
+ list.append("Item " + QString::number(i));
+}
+
+int IncrementalModel::rowCount(const QModelIndex & /* parent */) const
+{
+ return count;
+}
+
+QVariant IncrementalModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (index.row() >= list.size() || index.row() < 0)
+ return QVariant();
+
+ if (role == Qt::DisplayRole)
+ return list.at(index.row());
+ return QVariant();
+}
+
+bool IncrementalModel::canFetchMore(const QModelIndex & /* index */) const
+{
+ if (count < list.size())
+ return true;
+ else
+ return false;
+}
+
+void IncrementalModel::fetchMore(const QModelIndex & /* index */)
+{
+ int remainder = list.size() - count;
+ int itemsToFetch = qMin(5, remainder);
+
+ beginInsertRows(QModelIndex(), count, count+itemsToFetch-1);
+
+ count += itemsToFetch;
+
+ endInsertRows();
+}
diff --git a/tests/auto/declarative/qsglistview/incrementalmodel.h b/tests/auto/declarative/qsglistview/incrementalmodel.h
new file mode 100644
index 0000000000..9c4e7ddd4a
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/incrementalmodel.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef IncrementalModel_H
+#define IncrementalModel_H
+
+#include <QAbstractListModel>
+#include <QList>
+#include <QStringList>
+
+class IncrementalModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ IncrementalModel(QObject *parent = 0);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+protected:
+ bool canFetchMore(const QModelIndex &parent) const;
+ void fetchMore(const QModelIndex &parent);
+
+private:
+ QStringList list;
+ int count;
+};
+
+#endif
diff --git a/tests/auto/declarative/qsglistview/qsglistview.pro b/tests/auto/declarative/qsglistview/qsglistview.pro
new file mode 100644
index 0000000000..84b955eb55
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/qsglistview.pro
@@ -0,0 +1,16 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative
+macx:CONFIG -= app_bundle
+
+HEADERS += incrementalmodel.h
+SOURCES += tst_qsglistview.cpp incrementalmodel.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
diff --git a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp
new file mode 100644
index 0000000000..f697e61208
--- /dev/null
+++ b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp
@@ -0,0 +1,2698 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtGui/QStringListModel>
+#include <QtDeclarative/qsgview.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/private/qsgitem_p.h>
+#include <QtDeclarative/private/qsglistview_p.h>
+#include <QtDeclarative/private/qsgtext_p.h>
+#include <QtDeclarative/private/qsgvisualitemmodel_p.h>
+#include <QtDeclarative/private/qdeclarativelistmodel_p.h>
+#include <QtDeclarative/private/qlistmodelinterface_p.h>
+#include "../../../shared/util.h"
+#include "incrementalmodel.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_QSGListView : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QSGListView();
+
+private slots:
+ // Test both QListModelInterface and QAbstractItemModel model types
+ void qListModelInterface_items();
+ void qAbstractItemModel_items();
+
+ void qListModelInterface_changed();
+ void qAbstractItemModel_changed();
+
+ void qListModelInterface_inserted();
+ void qAbstractItemModel_inserted();
+
+ void qListModelInterface_removed();
+ void qAbstractItemModel_removed();
+
+ void qListModelInterface_moved();
+ void qAbstractItemModel_moved();
+
+ void qListModelInterface_clear();
+ void qAbstractItemModel_clear();
+
+ void itemList();
+ void currentIndex();
+ void noCurrentIndex();
+ void enforceRange();
+ void spacing();
+ void sections();
+ void sectionsDelegate();
+ void cacheBuffer();
+ void positionViewAtIndex();
+ void resetModel();
+ void propertyChanges();
+ void componentChanges();
+ void modelChanges();
+ void QTBUG_9791();
+ void manualHighlight();
+ void QTBUG_11105();
+ void header();
+ void footer();
+ void headerFooter();
+ void resizeView();
+ void sizeLessThan1();
+ void QTBUG_14821();
+ void resizeDelegate();
+ void QTBUG_16037();
+ void indexAt();
+ void incrementalModel();
+ void onAdd();
+ void onAdd_data();
+ void onRemove();
+ void onRemove_data();
+ void rightToLeft();
+ void test_mirroring();
+
+private:
+ template <class T> void items();
+ template <class T> void changed();
+ template <class T> void inserted();
+ template <class T> void removed(bool animated);
+ template <class T> void moved();
+ template <class T> void clear();
+ QSGView *createView();
+ template<typename T>
+ T *findItem(QSGItem *parent, const QString &id, int index=-1);
+ template<typename T>
+ QList<T*> findItems(QSGItem *parent, const QString &objectName);
+ void dumpTree(QSGItem *parent, int depth = 0);
+};
+
+class TestObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool error READ error WRITE setError NOTIFY changedError)
+ Q_PROPERTY(bool animate READ animate NOTIFY changedAnim)
+ Q_PROPERTY(bool invalidHighlight READ invalidHighlight NOTIFY changedHl)
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer NOTIFY changedCacheBuffer)
+
+public:
+ TestObject(QObject *parent = 0)
+ : QObject(parent), mError(true), mAnimate(false), mInvalidHighlight(false)
+ , mCacheBuffer(0) {}
+
+ bool error() const { return mError; }
+ void setError(bool err) { mError = err; emit changedError(); }
+
+ bool animate() const { return mAnimate; }
+ void setAnimate(bool anim) { mAnimate = anim; emit changedAnim(); }
+
+ bool invalidHighlight() const { return mInvalidHighlight; }
+ void setInvalidHighlight(bool invalid) { mInvalidHighlight = invalid; emit changedHl(); }
+
+ int cacheBuffer() const { return mCacheBuffer; }
+ void setCacheBuffer(int buffer) { mCacheBuffer = buffer; emit changedCacheBuffer(); }
+
+signals:
+ void changedError();
+ void changedAnim();
+ void changedHl();
+ void changedCacheBuffer();
+
+public:
+ bool mError;
+ bool mAnimate;
+ bool mInvalidHighlight;
+ int mCacheBuffer;
+};
+
+class TestModel : public QListModelInterface
+{
+ Q_OBJECT
+public:
+ TestModel(QObject *parent = 0) : QListModelInterface(parent) {}
+ ~TestModel() {}
+
+ enum Roles { Name, Number };
+
+ QString name(int index) const { return list.at(index).first; }
+ QString number(int index) const { return list.at(index).second; }
+
+ int count() const { return list.count(); }
+
+ QList<int> roles() const { return QList<int>() << Name << Number; }
+ QString toString(int role) const {
+ switch(role) {
+ case Name:
+ return "name";
+ case Number:
+ return "number";
+ default:
+ return "";
+ }
+ }
+
+ QVariant data(int index, int role) const
+ {
+ if (role==0)
+ return list.at(index).first;
+ if (role==1)
+ return list.at(index).second;
+ return QVariant();
+ }
+ QHash<int, QVariant> data(int index, const QList<int> &roles) const {
+ QHash<int,QVariant> returnHash;
+
+ for (int i = 0; i < roles.size(); ++i) {
+ int role = roles.at(i);
+ QVariant info;
+ switch(role) {
+ case Name:
+ info = list.at(index).first;
+ break;
+ case Number:
+ info = list.at(index).second;
+ break;
+ default:
+ break;
+ }
+ returnHash.insert(role, info);
+ }
+ return returnHash;
+ }
+
+ void addItem(const QString &name, const QString &number) {
+ list.append(QPair<QString,QString>(name, number));
+ emit itemsInserted(list.count()-1, 1);
+ }
+
+ void insertItem(int index, const QString &name, const QString &number) {
+ list.insert(index, QPair<QString,QString>(name, number));
+ emit itemsInserted(index, 1);
+ }
+
+ void removeItem(int index) {
+ list.removeAt(index);
+ emit itemsRemoved(index, 1);
+ }
+
+ void removeItems(int index, int count) {
+ int c = count;
+ while (c--)
+ list.removeAt(index);
+ emit itemsRemoved(index, count);
+ }
+
+ void moveItem(int from, int to) {
+ list.move(from, to);
+ emit itemsMoved(from, to, 1);
+ }
+
+ void modifyItem(int index, const QString &name, const QString &number) {
+ list[index] = QPair<QString,QString>(name, number);
+ emit itemsChanged(index, 1, roles());
+ }
+
+ void clear() {
+ int count = list.count();
+ list.clear();
+ emit itemsRemoved(0, count);
+ }
+
+private:
+ QList<QPair<QString,QString> > list;
+};
+
+
+class TestModel2 : public QAbstractListModel
+{
+public:
+ enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
+
+ TestModel2(QObject *parent=0) : QAbstractListModel(parent) {
+ QHash<int, QByteArray> roles;
+ roles[Name] = "name";
+ roles[Number] = "number";
+ setRoleNames(roles);
+ }
+
+ int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
+ QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
+ QVariant rv;
+ if (role == Name)
+ rv = list.at(index.row()).first;
+ else if (role == Number)
+ rv = list.at(index.row()).second;
+
+ return rv;
+ }
+
+ int count() const { return rowCount(); }
+ QString name(int index) const { return list.at(index).first; }
+ QString number(int index) const { return list.at(index).second; }
+
+ void addItem(const QString &name, const QString &number) {
+ emit beginInsertRows(QModelIndex(), list.count(), list.count());
+ list.append(QPair<QString,QString>(name, number));
+ emit endInsertRows();
+ }
+
+ void addItems(const QList<QPair<QString, QString> > &items) {
+ emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
+ for (int i=0; i<items.count(); i++)
+ list.append(QPair<QString,QString>(items[i].first, items[i].second));
+ emit endInsertRows();
+ }
+
+ void insertItem(int index, const QString &name, const QString &number) {
+ emit beginInsertRows(QModelIndex(), index, index);
+ list.insert(index, QPair<QString,QString>(name, number));
+ emit endInsertRows();
+ }
+
+ void removeItem(int index) {
+ emit beginRemoveRows(QModelIndex(), index, index);
+ list.removeAt(index);
+ emit endRemoveRows();
+ }
+
+ void removeItems(int index, int count) {
+ emit beginRemoveRows(QModelIndex(), index, index+count-1);
+ while (count--)
+ list.removeAt(index);
+ emit endRemoveRows();
+ }
+
+ void moveItem(int from, int to) {
+ emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
+ list.move(from, to);
+ emit endMoveRows();
+ }
+
+ void modifyItem(int idx, const QString &name, const QString &number) {
+ list[idx] = QPair<QString,QString>(name, number);
+ emit dataChanged(index(idx,0), index(idx,0));
+ }
+
+ void clear() {
+ int count = list.count();
+ emit beginRemoveRows(QModelIndex(), 0, count-1);
+ list.clear();
+ emit endRemoveRows();
+ }
+
+private:
+ QList<QPair<QString,QString> > list;
+};
+
+tst_QSGListView::tst_QSGListView()
+{
+}
+
+template <class T>
+void tst_QSGListView::items()
+{
+ QSGView *canvas = createView();
+
+ T model;
+ model.addItem("Fred", "12345");
+ model.addItem("John", "2345");
+ model.addItem("Bob", "54321");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
+ QTRY_VERIFY(testObject->error() == false);
+
+ QTRY_VERIFY(listview->highlightItem() != 0);
+ QTRY_COMPARE(listview->count(), model.count());
+ QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+
+ // current item should be first item
+ QTRY_COMPARE(listview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
+
+ for (int i = 0; i < model.count(); ++i) {
+ QSGText *name = findItem<QSGText>(contentItem, "textName", i);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ // switch to other delegate
+ testObject->setAnimate(true);
+ QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
+ QTRY_VERIFY(testObject->error() == false);
+ QTRY_VERIFY(listview->currentItem());
+
+ // set invalid highlight
+ testObject->setInvalidHighlight(true);
+ QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
+ QTRY_VERIFY(testObject->error() == false);
+ QTRY_VERIFY(listview->currentItem());
+ QTRY_VERIFY(listview->highlightItem() == 0);
+
+ // back to normal highlight
+ testObject->setInvalidHighlight(false);
+ QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
+ QTRY_VERIFY(testObject->error() == false);
+ QTRY_VERIFY(listview->currentItem());
+ QTRY_VERIFY(listview->highlightItem() != 0);
+
+ // set an empty model and confirm that items are destroyed
+ T model2;
+ ctxt->setContextProperty("testModel", &model2);
+
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ QTRY_VERIFY(itemCount == 0);
+
+ QTRY_COMPARE(listview->highlightResizeSpeed(), 1000.0);
+ QTRY_COMPARE(listview->highlightMoveSpeed(), 1000.0);
+
+ delete canvas;
+ delete testObject;
+}
+
+
+template <class T>
+void tst_QSGListView::changed()
+{
+ QSGView *canvas = createView();
+
+ T model;
+ model.addItem("Fred", "12345");
+ model.addItem("John", "2345");
+ model.addItem("Bob", "54321");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGFlickable *listview = findItem<QSGFlickable>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ model.modifyItem(1, "Will", "9876");
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(1));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(1));
+
+ delete canvas;
+ delete testObject;
+}
+
+template <class T>
+void tst_QSGListView::inserted()
+{
+ QSGView *canvas = createView();
+
+ T model;
+ model.addItem("Fred", "12345");
+ model.addItem("John", "2345");
+ model.addItem("Bob", "54321");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ model.insertItem(1, "Will", "9876");
+
+ QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(1));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(1));
+
+ // Confirm items positioned correctly
+ for (int i = 0; i < model.count(); ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ QTRY_COMPARE(item->y(), i*20.0);
+ }
+
+ model.insertItem(0, "Foo", "1111"); // zero index, and current item
+
+ QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+
+ name = findItem<QSGText>(contentItem, "textName", 0);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(0));
+ number = findItem<QSGText>(contentItem, "textNumber", 0);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(0));
+
+ QTRY_COMPARE(listview->currentIndex(), 1);
+
+ // Confirm items positioned correctly
+ for (int i = 0; i < model.count(); ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ QTRY_COMPARE(item->y(), i*20.0);
+ }
+
+ for (int i = model.count(); i < 30; ++i)
+ model.insertItem(i, "Hello", QString::number(i));
+
+ listview->setContentY(80);
+
+ // Insert item outside visible area
+ model.insertItem(1, "Hello", "1324");
+
+ QTRY_VERIFY(listview->contentY() == 80);
+
+ // Confirm items positioned correctly
+ for (int i = 5; i < 5+15; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.0 - 20.0);
+ }
+
+// QTRY_COMPARE(listview->contentItemHeight(), model.count() * 20.0);
+
+ delete canvas;
+ delete testObject;
+}
+
+template <class T>
+void tst_QSGListView::removed(bool animated)
+{
+ QSGView *canvas = createView();
+
+ T model;
+ for (int i = 0; i < 50; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ testObject->setAnimate(animated);
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ model.removeItem(1);
+
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(1));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(1));
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->y() == i*20);
+ }
+
+ // Remove first item (which is the current item);
+ model.removeItem(0); // post: top item starts at 20
+
+ QTest::qWait(300);
+
+ name = findItem<QSGText>(contentItem, "textName", 0);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(0));
+ number = findItem<QSGText>(contentItem, "textNumber", 0);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(0));
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(),i*20.0 + 20.0);
+ }
+
+ // Remove items not visible
+ model.removeItem(18);
+ qApp->processEvents();
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(),i*20.0+20.0);
+ }
+
+ // Remove items before visible
+ listview->setContentY(80);
+ listview->setCurrentIndex(10);
+
+ model.removeItem(1); // post: top item will be at 40
+ qApp->processEvents();
+
+ // Confirm items positioned correctly
+ for (int i = 2; i < 18; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(),40+i*20.0);
+ }
+
+ // Remove current index
+ QTRY_VERIFY(listview->currentIndex() == 9);
+ QSGItem *oldCurrent = listview->currentItem();
+ model.removeItem(9);
+
+ QTRY_COMPARE(listview->currentIndex(), 9);
+ QTRY_VERIFY(listview->currentItem() != oldCurrent);
+
+ listview->setContentY(40); // That's the top now
+ // let transitions settle.
+ QTest::qWait(300);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(),40+i*20.0);
+ }
+
+ // remove current item beyond visible items.
+ listview->setCurrentIndex(20);
+ listview->setContentY(40);
+ model.removeItem(20);
+
+ QTRY_COMPARE(listview->currentIndex(), 20);
+ QTRY_VERIFY(listview->currentItem() != 0);
+
+ // remove item before current, but visible
+ listview->setCurrentIndex(8);
+ oldCurrent = listview->currentItem();
+ model.removeItem(6);
+
+ QTRY_COMPARE(listview->currentIndex(), 7);
+ QTRY_VERIFY(listview->currentItem() == oldCurrent);
+
+ listview->setContentY(80);
+ QTest::qWait(300);
+
+ // remove all visible items
+ model.removeItems(1, 18);
+ QTest::qWait(300);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i+2);
+ if (!item) qWarning() << "Item" << i+2 << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(),80+i*20.0);
+ }
+
+ model.removeItems(1, 17);
+// QTest::qWait(300);
+
+ model.removeItems(2, 1);
+ model.addItem("New", "1");
+
+ QTRY_VERIFY(name = findItem<QSGText>(contentItem, "textName", model.count()-1));
+ QCOMPARE(name->text(), QString("New"));
+
+ delete canvas;
+ delete testObject;
+}
+
+template <class T>
+void tst_QSGListView::clear()
+{
+ QSGView *canvas = createView();
+
+ T model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ model.clear();
+
+ QTRY_VERIFY(listview->count() == 0);
+ QTRY_VERIFY(listview->currentItem() == 0);
+ QTRY_VERIFY(listview->contentY() == 0);
+ QVERIFY(listview->currentIndex() == -1);
+
+ // confirm sanity when adding an item to cleared list
+ model.addItem("New", "1");
+ QTRY_VERIFY(listview->count() == 1);
+ QVERIFY(listview->currentItem() != 0);
+ QVERIFY(listview->currentIndex() == 0);
+
+ delete canvas;
+ delete testObject;
+}
+
+
+template <class T>
+void tst_QSGListView::moved()
+{
+ QSGView *canvas = createView();
+
+ T model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ model.moveItem(1, 4);
+
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(1));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(1));
+
+ name = findItem<QSGText>(contentItem, "textName", 4);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(4));
+ number = findItem<QSGText>(contentItem, "textNumber", 4);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(4));
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->y() == i*20);
+ }
+
+ listview->setContentY(80);
+
+ // move outside visible area
+ model.moveItem(1, 18);
+
+ // Confirm items positioned correctly and indexes correct
+ for (int i = 3; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.0 + 20);
+ name = findItem<QSGText>(contentItem, "textName", i);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ number = findItem<QSGText>(contentItem, "textNumber", i);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ // move from outside visible into visible
+ model.moveItem(20, 4);
+
+ // Confirm items positioned correctly and indexes correct
+ for (int i = 3; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.0 + 20);
+ name = findItem<QSGText>(contentItem, "textName", i);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ number = findItem<QSGText>(contentItem, "textNumber", i);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QSGListView::enforceRange()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listview-enforcerange.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QTRY_COMPARE(listview->preferredHighlightBegin(), 100.0);
+ QTRY_COMPARE(listview->preferredHighlightEnd(), 100.0);
+ QTRY_COMPARE(listview->highlightRangeMode(), QSGListView::StrictlyEnforceRange);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // view should be positioned at the top of the range.
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(listview->contentY(), -100.0);
+
+ QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
+ QTRY_VERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(0));
+ QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
+ QTRY_VERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(0));
+
+ // Check currentIndex is updated when contentItem moves
+ listview->setContentY(20);
+
+ QTRY_COMPARE(listview->currentIndex(), 6);
+
+ // change model
+ TestModel model2;
+ for (int i = 0; i < 5; i++)
+ model2.addItem("Item" + QString::number(i), "");
+
+ ctxt->setContextProperty("testModel", &model2);
+ QCOMPARE(listview->count(), 5);
+
+ delete canvas;
+}
+
+void tst_QSGListView::spacing()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->y() == i*20);
+ }
+
+ listview->setSpacing(10);
+ QTRY_VERIFY(listview->spacing() == 10);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->y() == i*30);
+ }
+
+ listview->setSpacing(0);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.0);
+ }
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QSGListView::sections()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), QString::number(i/5));
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listview-sections.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), qreal(i*20 + ((i+4)/5) * 20));
+ QSGText *next = findItem<QSGText>(item, "nextSection");
+ QCOMPARE(next->text().toInt(), (i+1)/5);
+ }
+
+ QSignalSpy currentSectionChangedSpy(listview, SIGNAL(currentSectionChanged()));
+
+ // Remove section boundary
+ model.removeItem(5);
+
+ // New section header created
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 5);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->height(), 40.0);
+
+ model.insertItem(3, "New Item", "0");
+
+ // Section header moved
+ item = findItem<QSGItem>(contentItem, "wrapper", 5);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->height(), 20.0);
+
+ item = findItem<QSGItem>(contentItem, "wrapper", 6);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->height(), 40.0);
+
+ // insert item which will become a section header
+ model.insertItem(6, "Replace header", "1");
+
+ item = findItem<QSGItem>(contentItem, "wrapper", 6);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->height(), 40.0);
+
+ item = findItem<QSGItem>(contentItem, "wrapper", 7);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->height(), 20.0);
+
+ QTRY_COMPARE(listview->currentSection(), QString("0"));
+
+ listview->setContentY(140);
+ QTRY_COMPARE(listview->currentSection(), QString("1"));
+
+ QTRY_COMPARE(currentSectionChangedSpy.count(), 1);
+
+ listview->setContentY(20);
+ QTRY_COMPARE(listview->currentSection(), QString("0"));
+
+ QTRY_COMPARE(currentSectionChangedSpy.count(), 2);
+
+ item = findItem<QSGItem>(contentItem, "wrapper", 1);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->height(), 20.0);
+
+ // check that headers change when item changes
+ listview->setContentY(0);
+ model.modifyItem(0, "changed", "2");
+
+ item = findItem<QSGItem>(contentItem, "wrapper", 1);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->height(), 40.0);
+
+ delete canvas;
+}
+
+void tst_QSGListView::sectionsDelegate()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), QString::number(i/5));
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listview-sections_delegate.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), qreal(i*20 + ((i+5)/5) * 20));
+ QSGText *next = findItem<QSGText>(item, "nextSection");
+ QCOMPARE(next->text().toInt(), (i+1)/5);
+ }
+
+ for (int i = 0; i < 3; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "sect_" + QString::number(i));
+ QVERIFY(item);
+ QTRY_COMPARE(item->y(), qreal(i*20*6));
+ }
+
+ model.modifyItem(0, "One", "aaa");
+ model.modifyItem(1, "Two", "aaa");
+ model.modifyItem(2, "Three", "aaa");
+ model.modifyItem(3, "Four", "aaa");
+ model.modifyItem(4, "Five", "aaa");
+
+ for (int i = 0; i < 3; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem,
+ "sect_" + (i == 0 ? QString("aaa") : QString::number(i)));
+ QVERIFY(item);
+ QTRY_COMPARE(item->y(), qreal(i*20*6));
+ }
+
+ // remove section boundary
+ model.removeItem(5);
+ qApp->processEvents();
+ for (int i = 0; i < 3; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem,
+ "sect_" + (i == 0 ? QString("aaa") : QString::number(i)));
+ QVERIFY(item);
+ }
+
+ // QTBUG-17606
+ QList<QSGItem*> items = findItems<QSGItem>(contentItem, "sect_1");
+ QCOMPARE(items.count(), 1);
+
+ // QTBUG-17759
+ model.modifyItem(0, "One", "aaa");
+ model.modifyItem(1, "One", "aaa");
+ model.modifyItem(2, "One", "aaa");
+ model.modifyItem(3, "Four", "aaa");
+ model.modifyItem(4, "Four", "aaa");
+ model.modifyItem(5, "Four", "aaa");
+ model.modifyItem(6, "Five", "aaa");
+ model.modifyItem(7, "Five", "aaa");
+ model.modifyItem(8, "Five", "aaa");
+ model.modifyItem(9, "Two", "aaa");
+ model.modifyItem(10, "Two", "aaa");
+ model.modifyItem(11, "Two", "aaa");
+ QTRY_COMPARE(findItems<QSGItem>(contentItem, "sect_aaa").count(), 1);
+ canvas->rootObject()->setProperty("sectionProperty", "name");
+ // ensure view has settled.
+ QTRY_COMPARE(findItems<QSGItem>(contentItem, "sect_Four").count(), 1);
+ for (int i = 0; i < 4; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem,
+ "sect_" + model.name(i*3));
+ QVERIFY(item);
+ QTRY_COMPARE(item->y(), qreal(i*20*4));
+ }
+
+ // QTBUG-17769
+ model.removeItems(10, 20);
+ // ensure view has settled.
+ QTRY_COMPARE(findItems<QSGItem>(contentItem, "wrapper").count(), 10);
+ // Drag view up beyond bounds
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(20,20));
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(20,0), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(canvas, &mv);
+ }
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(20,-50), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(canvas, &mv);
+ }
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(20,-200), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(canvas, &mv);
+ }
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(20,-200));
+ // view should settle back at 0
+ QTRY_COMPARE(listview->contentY(), 0.0);
+
+ delete canvas;
+}
+
+void tst_QSGListView::currentIndex()
+{
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), QString::number(i));
+
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testWrap", QVariant(false));
+
+ QString filename(SRCDIR "/data/listview-initCurrent.qml");
+ canvas->setSource(QUrl::fromLocalFile(filename));
+
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // current item should be 20th item at startup
+ // and current item should be in view
+ QCOMPARE(listview->currentIndex(), 20);
+ QCOMPARE(listview->contentY(), 100.0);
+ QCOMPARE(listview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 20));
+ QCOMPARE(listview->highlightItem()->y(), listview->currentItem()->y());
+
+ // no wrap
+ listview->setCurrentIndex(0);
+ QCOMPARE(listview->currentIndex(), 0);
+ // confirm that the velocity is updated
+ QTRY_VERIFY(listview->verticalVelocity() != 0.0);
+
+ listview->incrementCurrentIndex();
+ QCOMPARE(listview->currentIndex(), 1);
+ listview->decrementCurrentIndex();
+ QCOMPARE(listview->currentIndex(), 0);
+
+ listview->decrementCurrentIndex();
+ QCOMPARE(listview->currentIndex(), 0);
+
+ // with wrap
+ ctxt->setContextProperty("testWrap", QVariant(true));
+ QVERIFY(listview->isWrapEnabled());
+
+ listview->decrementCurrentIndex();
+ QCOMPARE(listview->currentIndex(), model.count()-1);
+
+ QTRY_COMPARE(listview->contentY(), 280.0);
+
+ listview->incrementCurrentIndex();
+ QCOMPARE(listview->currentIndex(), 0);
+
+ QTRY_COMPARE(listview->contentY(), 0.0);
+
+ // Test keys
+ canvas->show();
+ qApp->setActiveWindow(canvas);
+#ifdef Q_WS_X11
+ // to be safe and avoid failing setFocus with window managers
+ qt_x11_wait_for_window_manager(canvas);
+#endif
+ QTRY_VERIFY(canvas->hasFocus());
+ qApp->processEvents();
+
+ QTest::keyClick(canvas, Qt::Key_Down);
+ QCOMPARE(listview->currentIndex(), 1);
+
+ QTest::keyClick(canvas, Qt::Key_Up);
+ QCOMPARE(listview->currentIndex(), 0);
+
+ // turn off auto highlight
+ listview->setHighlightFollowsCurrentItem(false);
+ QVERIFY(listview->highlightFollowsCurrentItem() == false);
+
+ QVERIFY(listview->highlightItem());
+ qreal hlPos = listview->highlightItem()->y();
+
+ listview->setCurrentIndex(4);
+ QTRY_COMPARE(listview->highlightItem()->y(), hlPos);
+
+ // insert item before currentIndex
+ listview->setCurrentIndex(28);
+ model.insertItem(0, "Foo", "1111");
+ QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
+
+ // check removing highlight by setting currentIndex to -1;
+ listview->setCurrentIndex(-1);
+
+ QCOMPARE(listview->currentIndex(), -1);
+ QVERIFY(!listview->highlightItem());
+ QVERIFY(!listview->currentItem());
+
+ delete canvas;
+}
+
+void tst_QSGListView::noCurrentIndex()
+{
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), QString::number(i));
+
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ QString filename(SRCDIR "/data/listview-noCurrent.qml");
+ canvas->setSource(QUrl::fromLocalFile(filename));
+
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // current index should be -1 at startup
+ // and we should not have a currentItem or highlightItem
+ QCOMPARE(listview->currentIndex(), -1);
+ QCOMPARE(listview->contentY(), 0.0);
+ QVERIFY(!listview->highlightItem());
+ QVERIFY(!listview->currentItem());
+
+ listview->setCurrentIndex(2);
+ QCOMPARE(listview->currentIndex(), 2);
+ QVERIFY(listview->highlightItem());
+ QVERIFY(listview->currentItem());
+
+ delete canvas;
+}
+
+void tst_QSGListView::itemList()
+{
+ QSGView *canvas = createView();
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/itemlist.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "view");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QSGVisualItemModel *model = canvas->rootObject()->findChild<QSGVisualItemModel*>("itemModel");
+ QTRY_VERIFY(model != 0);
+
+ QTRY_VERIFY(model->count() == 3);
+ QTRY_COMPARE(listview->currentIndex(), 0);
+
+ QSGItem *item = findItem<QSGItem>(contentItem, "item1");
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), 0.0);
+ QCOMPARE(item->height(), listview->height());
+
+ QSGText *text = findItem<QSGText>(contentItem, "text1");
+ QTRY_VERIFY(text);
+ QTRY_COMPARE(text->text(), QLatin1String("index: 0"));
+
+ listview->setCurrentIndex(2);
+
+ item = findItem<QSGItem>(contentItem, "item3");
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), 480.0);
+
+ text = findItem<QSGText>(contentItem, "text3");
+ QTRY_VERIFY(text);
+ QTRY_COMPARE(text->text(), QLatin1String("index: 2"));
+
+ delete canvas;
+}
+
+void tst_QSGListView::cacheBuffer()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+ QTRY_VERIFY(listview->delegate() != 0);
+ QTRY_VERIFY(listview->model() != 0);
+ QTRY_VERIFY(listview->highlight() != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->y() == i*20);
+ }
+
+ testObject->setCacheBuffer(400);
+ QTRY_VERIFY(listview->cacheBuffer() == 400);
+
+ int newItemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ QTRY_VERIFY(newItemCount > itemCount);
+
+ // Confirm items positioned correctly
+ for (int i = 0; i < model.count() && i < newItemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->y() == i*20);
+ }
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QSGListView::positionViewAtIndex()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 40; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.);
+ }
+
+ // Position on a currently visible item
+ listview->positionViewAtIndex(3, QSGListView::Beginning);
+ QTRY_COMPARE(listview->contentY(), 60.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.);
+ }
+
+ // Position on an item beyond the visible items
+ listview->positionViewAtIndex(22, QSGListView::Beginning);
+ QTRY_COMPARE(listview->contentY(), 440.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.);
+ }
+
+ // Position on an item that would leave empty space if positioned at the top
+ listview->positionViewAtIndex(28, QSGListView::Beginning);
+ QTRY_COMPARE(listview->contentY(), 480.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.);
+ }
+
+ // Position at the beginning again
+ listview->positionViewAtIndex(0, QSGListView::Beginning);
+ QTRY_COMPARE(listview->contentY(), 0.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.);
+ }
+
+ // Position at End using last index
+ listview->positionViewAtIndex(model.count()-1, QSGListView::End);
+ QTRY_COMPARE(listview->contentY(), 480.);
+
+ // Confirm items positioned correctly
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 24; i < model.count(); ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.);
+ }
+
+ // Position at End
+ listview->positionViewAtIndex(20, QSGListView::End);
+ QTRY_COMPARE(listview->contentY(), 100.);
+
+ // Position in Center
+ listview->positionViewAtIndex(15, QSGListView::Center);
+ QTRY_COMPARE(listview->contentY(), 150.);
+
+ // Ensure at least partially visible
+ listview->positionViewAtIndex(15, QSGListView::Visible);
+ QTRY_COMPARE(listview->contentY(), 150.);
+
+ listview->setContentY(302);
+ listview->positionViewAtIndex(15, QSGListView::Visible);
+ QTRY_COMPARE(listview->contentY(), 302.);
+
+ listview->setContentY(320);
+ listview->positionViewAtIndex(15, QSGListView::Visible);
+ QTRY_COMPARE(listview->contentY(), 300.);
+
+ listview->setContentY(85);
+ listview->positionViewAtIndex(20, QSGListView::Visible);
+ QTRY_COMPARE(listview->contentY(), 85.);
+
+ listview->setContentY(75);
+ listview->positionViewAtIndex(20, QSGListView::Visible);
+ QTRY_COMPARE(listview->contentY(), 100.);
+
+ // Ensure completely visible
+ listview->setContentY(120);
+ listview->positionViewAtIndex(20, QSGListView::Contain);
+ QTRY_COMPARE(listview->contentY(), 120.);
+
+ listview->setContentY(302);
+ listview->positionViewAtIndex(15, QSGListView::Contain);
+ QTRY_COMPARE(listview->contentY(), 300.);
+
+ listview->setContentY(85);
+ listview->positionViewAtIndex(20, QSGListView::Contain);
+ QTRY_COMPARE(listview->contentY(), 100.);
+
+ // positionAtBeginnging
+ listview->positionViewAtBeginning();
+ QTRY_COMPARE(listview->contentY(), 0.);
+
+ listview->setContentY(80);
+ canvas->rootObject()->setProperty("showHeader", true);
+ listview->positionViewAtBeginning();
+ QTRY_COMPARE(listview->contentY(), -30.);
+
+ // positionAtEnd
+ listview->positionViewAtEnd();
+ QTRY_COMPARE(listview->contentY(), 480.); // 40*20 - 320
+
+ listview->setContentY(80);
+ canvas->rootObject()->setProperty("showFooter", true);
+ listview->positionViewAtEnd();
+ QTRY_COMPARE(listview->contentY(), 510.);
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QSGListView::resetModel()
+{
+ QSGView *canvas = createView();
+
+ QStringList strings;
+ strings << "one" << "two" << "three";
+ QStringListModel model(strings);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaylist.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QTRY_COMPARE(listview->count(), model.rowCount());
+
+ for (int i = 0; i < model.rowCount(); ++i) {
+ QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
+ QTRY_VERIFY(display != 0);
+ QTRY_COMPARE(display->text(), strings.at(i));
+ }
+
+ strings.clear();
+ strings << "four" << "five" << "six" << "seven";
+ model.setStringList(strings);
+
+ QTRY_COMPARE(listview->count(), model.rowCount());
+
+ for (int i = 0; i < model.rowCount(); ++i) {
+ QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
+ QTRY_VERIFY(display != 0);
+ QTRY_COMPARE(display->text(), strings.at(i));
+ }
+
+ delete canvas;
+}
+
+void tst_QSGListView::propertyChanges()
+{
+ QSGView *canvas = createView();
+ QTRY_VERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
+
+ QSGListView *listView = canvas->rootObject()->findChild<QSGListView*>("listView");
+ QTRY_VERIFY(listView);
+
+ QSignalSpy highlightFollowsCurrentItemSpy(listView, SIGNAL(highlightFollowsCurrentItemChanged()));
+ QSignalSpy preferredHighlightBeginSpy(listView, SIGNAL(preferredHighlightBeginChanged()));
+ QSignalSpy preferredHighlightEndSpy(listView, SIGNAL(preferredHighlightEndChanged()));
+ QSignalSpy highlightRangeModeSpy(listView, SIGNAL(highlightRangeModeChanged()));
+ QSignalSpy keyNavigationWrapsSpy(listView, SIGNAL(keyNavigationWrapsChanged()));
+ QSignalSpy cacheBufferSpy(listView, SIGNAL(cacheBufferChanged()));
+ QSignalSpy snapModeSpy(listView, SIGNAL(snapModeChanged()));
+
+ QTRY_COMPARE(listView->highlightFollowsCurrentItem(), true);
+ QTRY_COMPARE(listView->preferredHighlightBegin(), 0.0);
+ QTRY_COMPARE(listView->preferredHighlightEnd(), 0.0);
+ QTRY_COMPARE(listView->highlightRangeMode(), QSGListView::ApplyRange);
+ QTRY_COMPARE(listView->isWrapEnabled(), true);
+ QTRY_COMPARE(listView->cacheBuffer(), 10);
+ QTRY_COMPARE(listView->snapMode(), QSGListView::SnapToItem);
+
+ listView->setHighlightFollowsCurrentItem(false);
+ listView->setPreferredHighlightBegin(1.0);
+ listView->setPreferredHighlightEnd(1.0);
+ listView->setHighlightRangeMode(QSGListView::StrictlyEnforceRange);
+ listView->setWrapEnabled(false);
+ listView->setCacheBuffer(3);
+ listView->setSnapMode(QSGListView::SnapOneItem);
+
+ QTRY_COMPARE(listView->highlightFollowsCurrentItem(), false);
+ QTRY_COMPARE(listView->preferredHighlightBegin(), 1.0);
+ QTRY_COMPARE(listView->preferredHighlightEnd(), 1.0);
+ QTRY_COMPARE(listView->highlightRangeMode(), QSGListView::StrictlyEnforceRange);
+ QTRY_COMPARE(listView->isWrapEnabled(), false);
+ QTRY_COMPARE(listView->cacheBuffer(), 3);
+ QTRY_COMPARE(listView->snapMode(), QSGListView::SnapOneItem);
+
+ QTRY_COMPARE(highlightFollowsCurrentItemSpy.count(),1);
+ QTRY_COMPARE(preferredHighlightBeginSpy.count(),1);
+ QTRY_COMPARE(preferredHighlightEndSpy.count(),1);
+ QTRY_COMPARE(highlightRangeModeSpy.count(),1);
+ QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
+ QTRY_COMPARE(cacheBufferSpy.count(),1);
+ QTRY_COMPARE(snapModeSpy.count(),1);
+
+ listView->setHighlightFollowsCurrentItem(false);
+ listView->setPreferredHighlightBegin(1.0);
+ listView->setPreferredHighlightEnd(1.0);
+ listView->setHighlightRangeMode(QSGListView::StrictlyEnforceRange);
+ listView->setWrapEnabled(false);
+ listView->setCacheBuffer(3);
+ listView->setSnapMode(QSGListView::SnapOneItem);
+
+ QTRY_COMPARE(highlightFollowsCurrentItemSpy.count(),1);
+ QTRY_COMPARE(preferredHighlightBeginSpy.count(),1);
+ QTRY_COMPARE(preferredHighlightEndSpy.count(),1);
+ QTRY_COMPARE(highlightRangeModeSpy.count(),1);
+ QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
+ QTRY_COMPARE(cacheBufferSpy.count(),1);
+ QTRY_COMPARE(snapModeSpy.count(),1);
+
+ delete canvas;
+}
+
+void tst_QSGListView::componentChanges()
+{
+ QSGView *canvas = createView();
+ QTRY_VERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
+
+ QSGListView *listView = canvas->rootObject()->findChild<QSGListView*>("listView");
+ QTRY_VERIFY(listView);
+
+ QDeclarativeComponent component(canvas->engine());
+ component.setData("import QtQuick 2.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
+
+ QDeclarativeComponent delegateComponent(canvas->engine());
+ delegateComponent.setData("import QtQuick 2.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
+
+ QSignalSpy highlightSpy(listView, SIGNAL(highlightChanged()));
+ QSignalSpy delegateSpy(listView, SIGNAL(delegateChanged()));
+ QSignalSpy headerSpy(listView, SIGNAL(headerChanged()));
+ QSignalSpy footerSpy(listView, SIGNAL(footerChanged()));
+
+ listView->setHighlight(&component);
+ listView->setHeader(&component);
+ listView->setFooter(&component);
+ listView->setDelegate(&delegateComponent);
+
+ QTRY_COMPARE(listView->highlight(), &component);
+ QTRY_COMPARE(listView->header(), &component);
+ QTRY_COMPARE(listView->footer(), &component);
+ QTRY_COMPARE(listView->delegate(), &delegateComponent);
+
+ QTRY_COMPARE(highlightSpy.count(),1);
+ QTRY_COMPARE(delegateSpy.count(),1);
+ QTRY_COMPARE(headerSpy.count(),1);
+ QTRY_COMPARE(footerSpy.count(),1);
+
+ listView->setHighlight(&component);
+ listView->setHeader(&component);
+ listView->setFooter(&component);
+ listView->setDelegate(&delegateComponent);
+
+ QTRY_COMPARE(highlightSpy.count(),1);
+ QTRY_COMPARE(delegateSpy.count(),1);
+ QTRY_COMPARE(headerSpy.count(),1);
+ QTRY_COMPARE(footerSpy.count(),1);
+
+ delete canvas;
+}
+
+void tst_QSGListView::modelChanges()
+{
+ QSGView *canvas = createView();
+ QTRY_VERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
+
+ QSGListView *listView = canvas->rootObject()->findChild<QSGListView*>("listView");
+ QTRY_VERIFY(listView);
+
+ QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
+ QTRY_VERIFY(alternateModel);
+ QVariant modelVariant = QVariant::fromValue(alternateModel);
+ QSignalSpy modelSpy(listView, SIGNAL(modelChanged()));
+
+ listView->setModel(modelVariant);
+ QTRY_COMPARE(listView->model(), modelVariant);
+ QTRY_COMPARE(modelSpy.count(),1);
+
+ listView->setModel(modelVariant);
+ QTRY_COMPARE(modelSpy.count(),1);
+
+ listView->setModel(QVariant());
+ QTRY_COMPARE(modelSpy.count(),2);
+
+// delete canvas;
+}
+
+void tst_QSGListView::QTBUG_9791()
+{
+ QSGView *canvas = createView();
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/strictlyenforcerange.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = qobject_cast<QSGListView*>(canvas->rootObject());
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+ QTRY_VERIFY(listview->delegate() != 0);
+ QTRY_VERIFY(listview->model() != 0);
+
+ QMetaObject::invokeMethod(listview, "fillModel");
+ qApp->processEvents();
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ QCOMPARE(itemCount, 3);
+
+ for (int i = 0; i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), i*300.0);
+ }
+
+ // check that view is positioned correctly
+ QTRY_COMPARE(listview->contentX(), 590.0);
+
+ delete canvas;
+}
+
+void tst_QSGListView::manualHighlight()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ QString filename(SRCDIR "/data/manual-highlight.qml");
+ canvas->setSource(QUrl::fromLocalFile(filename));
+
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QTRY_COMPARE(listview->currentIndex(), 0);
+ QTRY_COMPARE(listview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
+ QTRY_COMPARE(listview->highlightItem()->y() - 5, listview->currentItem()->y());
+
+ listview->setCurrentIndex(2);
+
+ QTRY_COMPARE(listview->currentIndex(), 2);
+ QTRY_COMPARE(listview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
+ QTRY_COMPARE(listview->highlightItem()->y() - 5, listview->currentItem()->y());
+
+ // QTBUG-15972
+ listview->positionViewAtIndex(3, QSGListView::Contain);
+
+ QTRY_COMPARE(listview->currentIndex(), 2);
+ QTRY_COMPARE(listview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
+ QTRY_COMPARE(listview->highlightItem()->y() - 5, listview->currentItem()->y());
+
+ delete canvas;
+}
+
+void tst_QSGListView::QTBUG_11105()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_VERIFY(item->y() == i*20);
+ }
+
+ listview->positionViewAtIndex(20, QSGListView::Beginning);
+ QCOMPARE(listview->contentY(), 280.);
+
+ TestModel model2;
+ for (int i = 0; i < 5; i++)
+ model2.addItem("Item" + QString::number(i), "");
+
+ ctxt->setContextProperty("testModel", &model2);
+
+ itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ QCOMPARE(itemCount, 5);
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QSGListView::header()
+{
+ {
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QSGText *header = findItem<QSGText>(contentItem, "header");
+ QVERIFY(header);
+ QCOMPARE(header->y(), 0.0);
+ QCOMPARE(header->height(), 20.0);
+
+ QCOMPARE(listview->contentY(), 0.0);
+
+ model.clear();
+ QTRY_COMPARE(header->y(), 0.0);
+
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
+
+ header = findItem<QSGText>(contentItem, "header");
+ QVERIFY(!header);
+ header = findItem<QSGText>(contentItem, "header2");
+ QVERIFY(header);
+
+ QCOMPARE(header->y(), 10.0);
+ QCOMPARE(header->height(), 10.0);
+ QCOMPARE(listview->contentY(), 10.0);
+
+ delete canvas;
+ }
+ {
+ QSGView *canvas = createView();
+
+ TestModel model;
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header1.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QSGText *header = findItem<QSGText>(contentItem, "header");
+ QVERIFY(header);
+ QCOMPARE(header->y(), 0.0);
+
+ QCOMPARE(listview->contentY(), 0.0);
+
+ model.clear();
+ QTRY_COMPARE(header->y(), 0.0);
+
+ delete canvas;
+ }
+}
+
+void tst_QSGListView::footer()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 3; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/footer.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QSGText *footer = findItem<QSGText>(contentItem, "footer");
+ QVERIFY(footer);
+ QCOMPARE(footer->y(), 60.0);
+ QCOMPARE(footer->height(), 30.0);
+
+ model.removeItem(1);
+ QTRY_COMPARE(footer->y(), 40.0);
+
+ model.clear();
+ QTRY_COMPARE(footer->y(), 0.0);
+
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
+
+ footer = findItem<QSGText>(contentItem, "footer");
+ QVERIFY(!footer);
+ footer = findItem<QSGText>(contentItem, "footer2");
+ QVERIFY(footer);
+
+ QCOMPARE(footer->y(), 600.0);
+ QCOMPARE(footer->height(), 20.0);
+ QCOMPARE(listview->contentY(), 0.0);
+
+ delete canvas;
+}
+
+class LVAccessor : public QSGListView
+{
+public:
+ qreal minY() const { return minYExtent(); }
+ qreal maxY() const { return maxYExtent(); }
+ qreal minX() const { return minXExtent(); }
+ qreal maxX() const { return maxXExtent(); }
+};
+
+void tst_QSGListView::headerFooter()
+{
+ {
+ // Vertical
+ QSGView *canvas = createView();
+
+ TestModel model;
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = qobject_cast<QSGListView*>(canvas->rootObject());
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QSGItem *header = findItem<QSGItem>(contentItem, "header");
+ QVERIFY(header);
+ QCOMPARE(header->y(), 0.0);
+
+ QSGItem *footer = findItem<QSGItem>(contentItem, "footer");
+ QVERIFY(footer);
+ QCOMPARE(footer->y(), 20.0);
+
+ QVERIFY(static_cast<LVAccessor*>(listview)->minY() == 0);
+ QVERIFY(static_cast<LVAccessor*>(listview)->maxY() == 0);
+
+ delete canvas;
+ }
+ {
+ // Horizontal
+ QSGView *canvas = createView();
+
+ TestModel model;
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml"));
+ canvas->rootObject()->setProperty("horizontal", true);
+ qApp->processEvents();
+
+ QSGListView *listview = qobject_cast<QSGListView*>(canvas->rootObject());
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QSGItem *header = findItem<QSGItem>(contentItem, "header");
+ QVERIFY(header);
+ QCOMPARE(header->x(), 0.0);
+
+ QSGItem *footer = findItem<QSGItem>(contentItem, "footer");
+ QVERIFY(footer);
+ QCOMPARE(footer->x(), 20.0);
+
+ QVERIFY(static_cast<LVAccessor*>(listview)->minX() == 0);
+ QVERIFY(static_cast<LVAccessor*>(listview)->maxX() == 0);
+
+ delete canvas;
+ }
+ {
+ // Horizontal RTL
+ QSGView *canvas = createView();
+
+ TestModel model;
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml"));
+ canvas->rootObject()->setProperty("horizontal", true);
+ canvas->rootObject()->setProperty("rtl", true);
+ qApp->processEvents();
+
+ QSGListView *listview = qobject_cast<QSGListView*>(canvas->rootObject());
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QSGItem *header = findItem<QSGItem>(contentItem, "header");
+ QVERIFY(header);
+ QCOMPARE(header->x(), -20.0);
+
+ QSGItem *footer = findItem<QSGItem>(contentItem, "footer");
+ QVERIFY(footer);
+ QCOMPARE(footer->x(), -50.0);
+
+ QCOMPARE(static_cast<LVAccessor*>(listview)->minX(), 240.);
+ QCOMPARE(static_cast<LVAccessor*>(listview)->maxX(), 240.);
+
+ delete canvas;
+ }
+}
+
+void tst_QSGListView::resizeView()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 40; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*20.);
+ }
+
+ QVariant heightRatio;
+ QMetaObject::invokeMethod(canvas->rootObject(), "heightRatio", Q_RETURN_ARG(QVariant, heightRatio));
+ QCOMPARE(heightRatio.toReal(), 0.4);
+
+ listview->setHeight(200);
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "heightRatio", Q_RETURN_ARG(QVariant, heightRatio));
+ QCOMPARE(heightRatio.toReal(), 0.25);
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QSGListView::sizeLessThan1()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/sizelessthan1.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->y(), i*0.5);
+ }
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QSGListView::QTBUG_14821()
+{
+ QSGView *canvas = createView();
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/qtbug14821.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = qobject_cast<QSGListView*>(canvas->rootObject());
+ QVERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ listview->decrementCurrentIndex();
+ QCOMPARE(listview->currentIndex(), 99);
+
+ listview->incrementCurrentIndex();
+ QCOMPARE(listview->currentIndex(), 0);
+
+ delete canvas;
+}
+
+void tst_QSGListView::resizeDelegate()
+{
+ QSGView *canvas = createView();
+ canvas->show();
+
+ QStringList strings;
+ for (int i = 0; i < 30; ++i)
+ strings << QString::number(i);
+ QStringListModel model(strings);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaylist.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QTRY_COMPARE(listview->count(), model.rowCount());
+
+ listview->setCurrentIndex(25);
+ listview->setContentY(0);
+
+ for (int i = 0; i < 16; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ QVERIFY(item != 0);
+ QCOMPARE(item->y(), i*20.0);
+ }
+
+ QCOMPARE(listview->currentItem()->y(), 500.0);
+ QTRY_COMPARE(listview->highlightItem()->y(), 500.0);
+
+ canvas->rootObject()->setProperty("delegateHeight", 30);
+ qApp->processEvents();
+
+ for (int i = 0; i < 11; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ QVERIFY(item != 0);
+ QTRY_COMPARE(item->y(), i*30.0);
+ }
+
+ QTRY_COMPARE(listview->currentItem()->y(), 750.0);
+ QTRY_COMPARE(listview->highlightItem()->y(), 750.0);
+
+ listview->setCurrentIndex(1);
+ listview->positionViewAtIndex(25, QSGListView::Beginning);
+ listview->positionViewAtIndex(5, QSGListView::Beginning);
+
+ for (int i = 5; i < 16; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ QVERIFY(item != 0);
+ QCOMPARE(item->y(), i*30.0);
+ }
+
+ QTRY_COMPARE(listview->currentItem()->y(), 30.0);
+ QTRY_COMPARE(listview->highlightItem()->y(), 30.0);
+
+ canvas->rootObject()->setProperty("delegateHeight", 20);
+ qApp->processEvents();
+
+ for (int i = 5; i < 11; ++i) {
+ QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
+ QVERIFY(item != 0);
+ QTRY_COMPARE(item->y(), 150 + (i-5)*20.0);
+ }
+
+ QTRY_COMPARE(listview->currentItem()->y(), 70.0);
+ QTRY_COMPARE(listview->highlightItem()->y(), 70.0);
+
+ delete canvas;
+}
+
+void tst_QSGListView::QTBUG_16037()
+{
+ QSGView *canvas = createView();
+ canvas->show();
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/qtbug16037.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "listview");
+ QTRY_VERIFY(listview != 0);
+
+ QVERIFY(listview->contentHeight() <= 0.0);
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "setModel");
+
+ QTRY_COMPARE(listview->contentHeight(), 80.0);
+
+ delete canvas;
+}
+
+void tst_QSGListView::indexAt()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 30; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QCOMPARE(listview->indexAt(0,0), 0);
+ QCOMPARE(listview->indexAt(0,19), 0);
+ QCOMPARE(listview->indexAt(239,19), 0);
+ QCOMPARE(listview->indexAt(0,20), 1);
+ QCOMPARE(listview->indexAt(240,20), -1);
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QSGListView::incrementalModel()
+{
+ QSGView *canvas = createView();
+
+ IncrementalModel model;
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaylist.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QTRY_COMPARE(listview->count(), 20);
+
+ listview->positionViewAtIndex(10, QSGListView::Beginning);
+
+ QTRY_COMPARE(listview->count(), 25);
+
+ delete canvas;
+}
+
+void tst_QSGListView::onAdd()
+{
+ QFETCH(int, initialItemCount);
+ QFETCH(int, itemsToAdd);
+
+ const int delegateHeight = 10;
+ TestModel2 model;
+
+ // these initial items should not trigger ListView.onAdd
+ for (int i=0; i<initialItemCount; i++)
+ model.addItem("dummy value", "dummy value");
+
+ QSGView *canvas = createView();
+ canvas->setFixedSize(200, delegateHeight * (initialItemCount + itemsToAdd));
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("delegateHeight", delegateHeight);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
+
+ QObject *object = canvas->rootObject();
+ object->setProperty("width", canvas->width());
+ object->setProperty("height", canvas->height());
+ qApp->processEvents();
+
+ QList<QPair<QString, QString> > items;
+ for (int i=0; i<itemsToAdd; i++)
+ items << qMakePair(QString("value %1").arg(i), QString::number(i));
+ model.addItems(items);
+
+ qApp->processEvents();
+
+ QVariantList result = object->property("addedDelegates").toList();
+ QCOMPARE(result.count(), items.count());
+ for (int i=0; i<items.count(); i++)
+ QCOMPARE(result[i].toString(), items[i].first);
+
+ delete canvas;
+}
+
+void tst_QSGListView::onAdd_data()
+{
+ QTest::addColumn<int>("initialItemCount");
+ QTest::addColumn<int>("itemsToAdd");
+
+ QTest::newRow("0, add 1") << 0 << 1;
+ QTest::newRow("0, add 2") << 0 << 2;
+ QTest::newRow("0, add 10") << 0 << 10;
+
+ QTest::newRow("1, add 1") << 1 << 1;
+ QTest::newRow("1, add 2") << 1 << 2;
+ QTest::newRow("1, add 10") << 1 << 10;
+
+ QTest::newRow("5, add 1") << 5 << 1;
+ QTest::newRow("5, add 2") << 5 << 2;
+ QTest::newRow("5, add 10") << 5 << 10;
+}
+
+void tst_QSGListView::onRemove()
+{
+ QFETCH(int, initialItemCount);
+ QFETCH(int, indexToRemove);
+ QFETCH(int, removeCount);
+
+ const int delegateHeight = 10;
+ TestModel2 model;
+ for (int i=0; i<initialItemCount; i++)
+ model.addItem(QString("value %1").arg(i), "dummy value");
+
+ QSGView *canvas = createView();
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("delegateHeight", delegateHeight);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
+ QObject *object = canvas->rootObject();
+
+ qApp->processEvents();
+
+ model.removeItems(indexToRemove, removeCount);
+ qApp->processEvents();
+ QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
+
+ delete canvas;
+}
+
+void tst_QSGListView::onRemove_data()
+{
+ QTest::addColumn<int>("initialItemCount");
+ QTest::addColumn<int>("indexToRemove");
+ QTest::addColumn<int>("removeCount");
+
+ QTest::newRow("remove first") << 1 << 0 << 1;
+ QTest::newRow("two items, remove first") << 2 << 0 << 1;
+ QTest::newRow("two items, remove last") << 2 << 1 << 1;
+ QTest::newRow("two items, remove all") << 2 << 0 << 2;
+
+ QTest::newRow("four items, remove first") << 4 << 0 << 1;
+ QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
+ QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
+ QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
+ QTest::newRow("four items, remove last") << 4 << 3 << 1;
+ QTest::newRow("four items, remove all") << 4 << 0 << 4;
+
+ QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
+ QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
+ QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
+}
+
+void tst_QSGListView::rightToLeft()
+{
+ QSGView *canvas = createView();
+ canvas->setFixedSize(640,320);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/rightToLeft.qml"));
+ qApp->processEvents();
+
+ QVERIFY(canvas->rootObject() != 0);
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "view");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QSGVisualItemModel *model = canvas->rootObject()->findChild<QSGVisualItemModel*>("itemModel");
+ QTRY_VERIFY(model != 0);
+
+ QTRY_VERIFY(model->count() == 3);
+ QTRY_COMPARE(listview->currentIndex(), 0);
+
+ // initial position at first item, right edge aligned
+ QCOMPARE(listview->contentX(), -640.);
+
+ QSGItem *item = findItem<QSGItem>(contentItem, "item1");
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), -100.0);
+ QCOMPARE(item->height(), listview->height());
+
+ QSGText *text = findItem<QSGText>(contentItem, "text1");
+ QTRY_VERIFY(text);
+ QTRY_COMPARE(text->text(), QLatin1String("index: 0"));
+
+ listview->setCurrentIndex(2);
+
+ item = findItem<QSGItem>(contentItem, "item3");
+ QTRY_VERIFY(item);
+ QTRY_COMPARE(item->x(), -540.0);
+
+ text = findItem<QSGText>(contentItem, "text3");
+ QTRY_VERIFY(text);
+ QTRY_COMPARE(text->text(), QLatin1String("index: 2"));
+
+ QCOMPARE(listview->contentX(), -640.);
+
+ // Ensure resizing maintains position relative to right edge
+ qobject_cast<QSGItem*>(canvas->rootObject())->setWidth(600);
+ QTRY_COMPARE(listview->contentX(), -600.);
+
+ delete canvas;
+}
+
+void tst_QSGListView::test_mirroring()
+{
+ QSGView *canvasA = createView();
+ canvasA->setSource(QUrl::fromLocalFile(SRCDIR "/data/rightToLeft.qml"));
+ QSGListView *listviewA = findItem<QSGListView>(canvasA->rootObject(), "view");
+ QTRY_VERIFY(listviewA != 0);
+
+ QSGView *canvasB = createView();
+ canvasB->setSource(QUrl::fromLocalFile(SRCDIR "/data/rightToLeft.qml"));
+ QSGListView *listviewB = findItem<QSGListView>(canvasB->rootObject(), "view");
+ QTRY_VERIFY(listviewA != 0);
+ qApp->processEvents();
+
+ QList<QString> objectNames;
+ objectNames << "item1" << "item2"; // << "item3"
+
+ listviewA->setProperty("layoutDirection", Qt::LeftToRight);
+ listviewB->setProperty("layoutDirection", Qt::RightToLeft);
+ QCOMPARE(listviewA->layoutDirection(), listviewA->effectiveLayoutDirection());
+
+ // LTR != RTL
+ foreach(const QString objectName, objectNames)
+ QVERIFY(findItem<QSGItem>(listviewA, objectName)->x() != findItem<QSGItem>(listviewB, objectName)->x());
+
+ listviewA->setProperty("layoutDirection", Qt::LeftToRight);
+ listviewB->setProperty("layoutDirection", Qt::LeftToRight);
+
+ // LTR == LTR
+ foreach(const QString objectName, objectNames)
+ QCOMPARE(findItem<QSGItem>(listviewA, objectName)->x(), findItem<QSGItem>(listviewB, objectName)->x());
+
+ QVERIFY(listviewB->layoutDirection() == listviewB->effectiveLayoutDirection());
+ QSGItemPrivate::get(listviewB)->setLayoutMirror(true);
+ QVERIFY(listviewB->layoutDirection() != listviewB->effectiveLayoutDirection());
+
+ // LTR != LTR+mirror
+ foreach(const QString objectName, objectNames)
+ QVERIFY(findItem<QSGItem>(listviewA, objectName)->x() != findItem<QSGItem>(listviewB, objectName)->x());
+
+ listviewA->setProperty("layoutDirection", Qt::RightToLeft);
+
+ // RTL == LTR+mirror
+ foreach(const QString objectName, objectNames)
+ QCOMPARE(findItem<QSGItem>(listviewA, objectName)->x(), findItem<QSGItem>(listviewB, objectName)->x());
+
+ listviewB->setProperty("layoutDirection", Qt::RightToLeft);
+
+ // RTL != RTL+mirror
+ foreach(const QString objectName, objectNames)
+ QVERIFY(findItem<QSGItem>(listviewA, objectName)->x() != findItem<QSGItem>(listviewB, objectName)->x());
+
+ listviewA->setProperty("layoutDirection", Qt::LeftToRight);
+
+ // LTR == RTL+mirror
+ foreach(const QString objectName, objectNames)
+ QCOMPARE(findItem<QSGItem>(listviewA, objectName)->x(), findItem<QSGItem>(listviewB, objectName)->x());
+
+ delete canvasA;
+ delete canvasB;
+}
+
+void tst_QSGListView::qListModelInterface_items()
+{
+ items<TestModel>();
+}
+
+void tst_QSGListView::qAbstractItemModel_items()
+{
+ items<TestModel2>();
+}
+
+void tst_QSGListView::qListModelInterface_changed()
+{
+ changed<TestModel>();
+}
+
+void tst_QSGListView::qAbstractItemModel_changed()
+{
+ changed<TestModel2>();
+}
+
+void tst_QSGListView::qListModelInterface_inserted()
+{
+ inserted<TestModel>();
+}
+
+void tst_QSGListView::qAbstractItemModel_inserted()
+{
+ inserted<TestModel2>();
+}
+
+void tst_QSGListView::qListModelInterface_removed()
+{
+ removed<TestModel>(false);
+ removed<TestModel>(true);
+}
+
+void tst_QSGListView::qAbstractItemModel_removed()
+{
+ removed<TestModel2>(false);
+ removed<TestModel2>(true);
+}
+
+void tst_QSGListView::qListModelInterface_moved()
+{
+ moved<TestModel>();
+}
+
+void tst_QSGListView::qAbstractItemModel_moved()
+{
+ moved<TestModel2>();
+}
+
+void tst_QSGListView::qListModelInterface_clear()
+{
+ clear<TestModel>();
+}
+
+void tst_QSGListView::qAbstractItemModel_clear()
+{
+ clear<TestModel2>();
+}
+
+QSGView *tst_QSGListView::createView()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ return canvas;
+}
+
+/*
+ Find an item with the specified objectName. If index is supplied then the
+ item must also evaluate the {index} expression equal to index
+*/
+template<typename T>
+T *tst_QSGListView::findItem(QSGItem *parent, const QString &objectName, int index)
+{
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->childItems().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ if (index != -1) {
+ QDeclarativeExpression e(qmlContext(item), item, "index");
+ if (e.evaluate().toInt() == index)
+ return static_cast<T*>(item);
+ } else {
+ return static_cast<T*>(item);
+ }
+ }
+ item = findItem<T>(item, objectName, index);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+}
+
+template<typename T>
+QList<T*> tst_QSGListView::findItems(QSGItem *parent, const QString &objectName)
+{
+ QList<T*> items;
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->childItems().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item || !item->isVisible())
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
+ items.append(static_cast<T*>(item));
+ items += findItems<T>(item, objectName);
+ }
+
+ return items;
+}
+
+void tst_QSGListView::dumpTree(QSGItem *parent, int depth)
+{
+ static QString padding(" ");
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ qDebug() << padding.left(depth*2) << item;
+ dumpTree(item, depth+1);
+ }
+}
+
+
+QTEST_MAIN(tst_QSGListView)
+
+#include "tst_qsglistview.moc"
diff --git a/tests/auto/declarative/qsgloader/data/AnchoredLoader.qml b/tests/auto/declarative/qsgloader/data/AnchoredLoader.qml
new file mode 100644
index 0000000000..1a2a620d7f
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/AnchoredLoader.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 300
+ height: 200
+ color: "blue"
+ Loader {
+ objectName: "loader"
+ anchors.fill: parent
+ sourceComponent: Component {
+ Rectangle { color: "red"; objectName: "sourceElement" }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgloader/data/BlueRect.qml b/tests/auto/declarative/qsgloader/data/BlueRect.qml
new file mode 100644
index 0000000000..e96ac00f21
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/BlueRect.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Rectangle {
+ objectName: "blue"
+ width: 100
+ height: 100
+ color: "blue"
+}
diff --git a/tests/auto/declarative/qsgloader/data/CreationContextLoader.qml b/tests/auto/declarative/qsgloader/data/CreationContextLoader.qml
new file mode 100644
index 0000000000..4dd73e797c
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/CreationContextLoader.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+
+Loader {
+ id: myLoader
+ property int testProperty: 1912
+ sourceComponent: loaderComponent
+ Component {
+ id: loaderComponent
+ Item {
+ Component.onCompleted: {
+ test = (myLoader.testProperty == 1912);
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgloader/data/GraphicsWidget250x250.qml b/tests/auto/declarative/qsgloader/data/GraphicsWidget250x250.qml
new file mode 100644
index 0000000000..dae8e3fbbb
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/GraphicsWidget250x250.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QGraphicsWidget {
+ size: "250x250"
+}
diff --git a/tests/auto/declarative/qsgloader/data/GreenRect.qml b/tests/auto/declarative/qsgloader/data/GreenRect.qml
new file mode 100644
index 0000000000..99cefaf176
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/GreenRect.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 100; height: 100
+ color: "green"
+ Component.onCompleted: myLoader.source = "BlueRect.qml"
+}
diff --git a/tests/auto/declarative/qsgloader/data/NoResize.qml b/tests/auto/declarative/qsgloader/data/NoResize.qml
new file mode 100644
index 0000000000..9b3ea6410b
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/NoResize.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Item {
+ width: 200; height: 80
+ Loader {
+ source: "Rect120x60.qml"
+ }
+}
diff --git a/tests/auto/declarative/qsgloader/data/NoResizeGraphicsWidget.qml b/tests/auto/declarative/qsgloader/data/NoResizeGraphicsWidget.qml
new file mode 100644
index 0000000000..c0f51d8c35
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/NoResizeGraphicsWidget.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ width: 200
+ height: 80
+ Loader {
+ source: "GraphicsWidget250x250.qml"
+ }
+}
diff --git a/tests/auto/declarative/qsgloader/data/QTBUG_16928.qml b/tests/auto/declarative/qsgloader/data/QTBUG_16928.qml
new file mode 100644
index 0000000000..903d7f0812
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/QTBUG_16928.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Rectangle {
+ color: "green"
+ width: loader.implicitWidth+50
+ height: loader.implicitHeight+50
+
+ Loader {
+ id: loader
+ sourceComponent: Item {
+ anchors.centerIn: parent
+
+ implicitWidth: 200
+ implicitHeight: 200
+ Rectangle {
+ color: "red"
+ anchors.fill: parent
+ }
+ }
+ anchors.fill: parent
+ anchors.margins: 15
+ }
+}
diff --git a/tests/auto/declarative/qsgloader/data/QTBUG_17114.qml b/tests/auto/declarative/qsgloader/data/QTBUG_17114.qml
new file mode 100644
index 0000000000..7402037553
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/QTBUG_17114.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Rectangle {
+ property real loaderWidth: loader.width
+ property real loaderHeight: loader.height
+ width: 200
+ height: 200
+
+ Loader {
+ id: loader
+ sourceComponent: Item {
+ property real iwidth: 32
+ property real iheight: 32
+ width: iwidth
+ height: iheight
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgloader/data/Rect120x60.qml b/tests/auto/declarative/qsgloader/data/Rect120x60.qml
new file mode 100644
index 0000000000..fc9e447e69
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/Rect120x60.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 120
+ height:60
+}
diff --git a/tests/auto/declarative/qsgloader/data/SetSourceComponent.qml b/tests/auto/declarative/qsgloader/data/SetSourceComponent.qml
new file mode 100644
index 0000000000..83cc358f7d
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/SetSourceComponent.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ function clear() {
+ loader.sourceComponent = undefined
+ }
+ Component { id: comp; Rectangle { width: 100; height: 50 } }
+ Loader { id: loader; sourceComponent: comp }
+}
diff --git a/tests/auto/declarative/qsgloader/data/SizeGraphicsWidgetToLoader.qml b/tests/auto/declarative/qsgloader/data/SizeGraphicsWidgetToLoader.qml
new file mode 100644
index 0000000000..2a63b4d34f
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/SizeGraphicsWidgetToLoader.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Loader {
+ width: 200
+ height: 80
+ source: "GraphicsWidget250x250.qml"
+}
diff --git a/tests/auto/declarative/qsgloader/data/SizeLoaderToGraphicsWidget.qml b/tests/auto/declarative/qsgloader/data/SizeLoaderToGraphicsWidget.qml
new file mode 100644
index 0000000000..a9875d8e21
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/SizeLoaderToGraphicsWidget.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Loader {
+ source: "GraphicsWidget250x250.qml"
+}
diff --git a/tests/auto/declarative/qsgloader/data/SizeToItem.qml b/tests/auto/declarative/qsgloader/data/SizeToItem.qml
new file mode 100644
index 0000000000..866365754f
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/SizeToItem.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Loader {
+ source: "Rect120x60.qml"
+}
diff --git a/tests/auto/declarative/qsgloader/data/SizeToLoader.qml b/tests/auto/declarative/qsgloader/data/SizeToLoader.qml
new file mode 100644
index 0000000000..dad18c6939
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/SizeToLoader.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+Loader {
+ width: 200; height: 80
+ source: "Rect120x60.qml"
+}
diff --git a/tests/auto/declarative/qsgloader/data/VmeError.qml b/tests/auto/declarative/qsgloader/data/VmeError.qml
new file mode 100644
index 0000000000..0443aa9054
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/VmeError.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 100; height: 100; color: "red"
+ signal somethingHappened
+ onSomethingHappened: QtObject {}
+}
diff --git a/tests/auto/declarative/qsgloader/data/crash.qml b/tests/auto/declarative/qsgloader/data/crash.qml
new file mode 100644
index 0000000000..e6ddc33a10
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/crash.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 400
+
+ function setLoaderSource() {
+ myLoader.source = "GreenRect.qml"
+ }
+
+ Loader {
+ id: myLoader
+ }
+}
diff --git a/tests/auto/declarative/qsgloader/data/creationContext.qml b/tests/auto/declarative/qsgloader/data/creationContext.qml
new file mode 100644
index 0000000000..17a596cc74
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/creationContext.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Item {
+ property bool test: false
+
+ CreationContextLoader {
+ }
+}
diff --git a/tests/auto/declarative/qsgloader/data/differentorigin.qml b/tests/auto/declarative/qsgloader/data/differentorigin.qml
new file mode 100644
index 0000000000..56a3034fe0
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/differentorigin.qml
@@ -0,0 +1,3 @@
+import QtQuick 2.0
+
+Loader { source: "http://evil.place/evil.qml" }
diff --git a/tests/auto/declarative/qsgloader/data/implicitSize.qml b/tests/auto/declarative/qsgloader/data/implicitSize.qml
new file mode 100644
index 0000000000..5c8c8348ed
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/implicitSize.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+Rectangle {
+ property real implWidth: 0
+ property real implHeight: 0
+ color: "green"
+ width: loader.implicitWidth+50
+ height: loader.implicitHeight+50
+
+ Loader {
+ id: loader
+ sourceComponent: Item {
+ anchors.centerIn: parent
+
+ implicitWidth: 100
+ implicitHeight: 100
+ Rectangle {
+ color: "red"
+ anchors.fill: parent
+ }
+ }
+
+ anchors.fill: parent
+ anchors.margins: 50
+ onImplicitWidthChanged: implWidth = implicitWidth
+ onImplicitHeightChanged: implHeight = loader.implicitHeight
+ }
+}
diff --git a/tests/auto/declarative/qsgloader/data/nonItem.qml b/tests/auto/declarative/qsgloader/data/nonItem.qml
new file mode 100644
index 0000000000..8cfa0d8efb
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/nonItem.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Loader {
+ sourceComponent: QtObject {}
+}
diff --git a/tests/auto/declarative/qsgloader/data/qmldir b/tests/auto/declarative/qsgloader/data/qmldir
new file mode 100644
index 0000000000..bf42b507c0
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/qmldir
@@ -0,0 +1 @@
+# For tst_QDeclarativeLoader::networkRequestUrl; no types needed though.
diff --git a/tests/auto/declarative/qsgloader/data/sameorigin-load.qml b/tests/auto/declarative/qsgloader/data/sameorigin-load.qml
new file mode 100644
index 0000000000..3332500be6
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/sameorigin-load.qml
@@ -0,0 +1,3 @@
+import QtQuick 2.0
+
+Item { }
diff --git a/tests/auto/declarative/qsgloader/data/sameorigin.qml b/tests/auto/declarative/qsgloader/data/sameorigin.qml
new file mode 100644
index 0000000000..84846b6aba
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/sameorigin.qml
@@ -0,0 +1,3 @@
+import QtQuick 2.0
+
+Loader { source: "sameorigin-load.qml" }
diff --git a/tests/auto/declarative/qsgloader/data/vmeErrors.qml b/tests/auto/declarative/qsgloader/data/vmeErrors.qml
new file mode 100644
index 0000000000..8e6c89dc8e
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/data/vmeErrors.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+Loader {
+ source: "VmeError.qml"
+}
+
diff --git a/tests/auto/declarative/qsgloader/qsgloader.pro b/tests/auto/declarative/qsgloader/qsgloader.pro
new file mode 100644
index 0000000000..25093658de
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/qsgloader.pro
@@ -0,0 +1,19 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui network
+macx:CONFIG -= app_bundle
+
+INCLUDEPATH += ../shared/
+HEADERS += ../shared/testhttpserver.h
+SOURCES += tst_qsgloader.cpp \
+ ../shared/testhttpserver.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgloader/tst_qsgloader.cpp b/tests/auto/declarative/qsgloader/tst_qsgloader.cpp
new file mode 100644
index 0000000000..5f4adcbd95
--- /dev/null
+++ b/tests/auto/declarative/qsgloader/tst_qsgloader.cpp
@@ -0,0 +1,559 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+
+#include <QSignalSpy>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <private/qsgloader_p.h>
+#include "testhttpserver.h"
+#include "../../../shared/util.h"
+
+#define SERVER_PORT 14450
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+inline QUrl TEST_FILE(const QString &filename)
+{
+ return QUrl::fromLocalFile(QLatin1String(SRCDIR) + QLatin1String("/data/") + filename);
+}
+
+class tst_QSGLoader : public QObject
+
+{
+ Q_OBJECT
+public:
+ tst_QSGLoader();
+
+private slots:
+ void sourceOrComponent();
+ void sourceOrComponent_data();
+ void clear();
+ void urlToComponent();
+ void componentToUrl();
+ void anchoredLoader();
+ void sizeLoaderToItem();
+ void sizeItemToLoader();
+ void noResize();
+ void networkRequestUrl();
+ void failNetworkRequest();
+// void networkComponent();
+
+ void deleteComponentCrash();
+ void nonItem();
+ void vmeErrors();
+ void creationContext();
+ void QTBUG_16928();
+ void implicitSize();
+ void QTBUG_17114();
+
+private:
+ QDeclarativeEngine engine;
+};
+
+
+tst_QSGLoader::tst_QSGLoader()
+{
+}
+
+void tst_QSGLoader::sourceOrComponent()
+{
+ QFETCH(QString, sourceDefinition);
+ QFETCH(QUrl, sourceUrl);
+ QFETCH(QString, errorString);
+
+ bool error = !errorString.isEmpty();
+ if (error)
+ QTest::ignoreMessage(QtWarningMsg, errorString.toUtf8().constData());
+
+ QDeclarativeComponent component(&engine);
+ component.setData(QByteArray(
+ "import QtQuick 2.0\n"
+ "Loader {\n"
+ " property int onItemChangedCount: 0\n"
+ " property int onSourceChangedCount: 0\n"
+ " property int onStatusChangedCount: 0\n"
+ " property int onProgressChangedCount: 0\n"
+ " property int onLoadedCount: 0\n")
+ + sourceDefinition.toUtf8()
+ + QByteArray(
+ " onItemChanged: onItemChangedCount += 1\n"
+ " onSourceChanged: onSourceChangedCount += 1\n"
+ " onStatusChanged: onStatusChangedCount += 1\n"
+ " onProgressChanged: onProgressChangedCount += 1\n"
+ " onLoaded: onLoadedCount += 1\n"
+ "}")
+ , TEST_FILE(""));
+
+ QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
+ QVERIFY(loader != 0);
+ QCOMPARE(loader->item() == 0, error);
+ QCOMPARE(loader->source(), sourceUrl);
+ QCOMPARE(loader->progress(), 1.0);
+
+ QCOMPARE(loader->status(), error ? QSGLoader::Error : QSGLoader::Ready);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), error ? 0: 1);
+
+ if (!error) {
+ QDeclarativeComponent *c = qobject_cast<QDeclarativeComponent*>(loader->children().at(0));
+ QVERIFY(c);
+ QCOMPARE(loader->sourceComponent(), c);
+ }
+
+ QCOMPARE(loader->property("onSourceChangedCount").toInt(), 1);
+ QCOMPARE(loader->property("onStatusChangedCount").toInt(), 1);
+ QCOMPARE(loader->property("onProgressChangedCount").toInt(), 1);
+
+ QCOMPARE(loader->property("onItemChangedCount").toInt(), error ? 0 : 1);
+ QCOMPARE(loader->property("onLoadedCount").toInt(), error ? 0 : 1);
+
+ delete loader;
+}
+
+void tst_QSGLoader::sourceOrComponent_data()
+{
+ QTest::addColumn<QString>("sourceDefinition");
+ QTest::addColumn<QUrl>("sourceUrl");
+ QTest::addColumn<QString>("errorString");
+
+ QTest::newRow("source") << "source: 'Rect120x60.qml'\n" << QUrl::fromLocalFile(SRCDIR "/data/Rect120x60.qml") << "";
+ QTest::newRow("sourceComponent") << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << "";
+
+ QTest::newRow("invalid source") << "source: 'IDontExist.qml'\n" << QUrl::fromLocalFile(SRCDIR "/data/IDontExist.qml")
+ << QString(QUrl::fromLocalFile(SRCDIR "/data/IDontExist.qml").toString() + ": File not found");
+}
+
+void tst_QSGLoader::clear()
+{
+ {
+ QDeclarativeComponent component(&engine);
+ component.setData(QByteArray(
+ "import QtQuick 2.0\n"
+ " Loader { id: loader\n"
+ " source: 'Rect120x60.qml'\n"
+ " Timer { interval: 200; running: true; onTriggered: loader.source = '' }\n"
+ " }")
+ , TEST_FILE(""));
+ QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
+ QVERIFY(loader != 0);
+ QVERIFY(loader->item());
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
+
+ QTRY_VERIFY(loader->item() == 0);
+ QCOMPARE(loader->progress(), 0.0);
+ QCOMPARE(loader->status(), QSGLoader::Null);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 0);
+
+ delete loader;
+ }
+ {
+ QDeclarativeComponent component(&engine, TEST_FILE("/SetSourceComponent.qml"));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+
+ QSGLoader *loader = qobject_cast<QSGLoader*>(item->QSGItem::childItems().at(0));
+ QVERIFY(loader);
+ QVERIFY(loader->item());
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
+
+ loader->setSourceComponent(0);
+
+ QVERIFY(loader->item() == 0);
+ QCOMPARE(loader->progress(), 0.0);
+ QCOMPARE(loader->status(), QSGLoader::Null);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 0);
+
+ delete item;
+ }
+ {
+ QDeclarativeComponent component(&engine, TEST_FILE("/SetSourceComponent.qml"));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+
+ QSGLoader *loader = qobject_cast<QSGLoader*>(item->QSGItem::childItems().at(0));
+ QVERIFY(loader);
+ QVERIFY(loader->item());
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
+
+ QMetaObject::invokeMethod(item, "clear");
+
+ QVERIFY(loader->item() == 0);
+ QCOMPARE(loader->progress(), 0.0);
+ QCOMPARE(loader->status(), QSGLoader::Null);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 0);
+
+ delete item;
+ }
+}
+
+void tst_QSGLoader::urlToComponent()
+{
+ QDeclarativeComponent component(&engine);
+ component.setData(QByteArray("import QtQuick 2.0\n"
+ "Loader {\n"
+ " id: loader\n"
+ " Component { id: myComp; Rectangle { width: 10; height: 10 } }\n"
+ " source: \"Rect120x60.qml\"\n"
+ " Timer { interval: 100; running: true; onTriggered: loader.sourceComponent = myComp }\n"
+ "}" )
+ , TEST_FILE(""));
+ QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
+ QTest::qWait(200);
+ QTRY_VERIFY(loader != 0);
+ QVERIFY(loader->item());
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
+ QCOMPARE(loader->width(), 10.0);
+ QCOMPARE(loader->height(), 10.0);
+
+ delete loader;
+}
+
+void tst_QSGLoader::componentToUrl()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("/SetSourceComponent.qml"));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+
+ QSGLoader *loader = qobject_cast<QSGLoader*>(item->QSGItem::childItems().at(0));
+ QVERIFY(loader);
+ QVERIFY(loader->item());
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
+
+ loader->setSource(TEST_FILE("/Rect120x60.qml"));
+ QVERIFY(loader->item());
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
+ QCOMPARE(loader->width(), 120.0);
+ QCOMPARE(loader->height(), 60.0);
+
+ delete item;
+}
+
+void tst_QSGLoader::anchoredLoader()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("/AnchoredLoader.qml"));
+ QSGItem *rootItem = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(rootItem != 0);
+ QSGItem *loader = rootItem->findChild<QSGItem*>("loader");
+ QSGItem *sourceElement = rootItem->findChild<QSGItem*>("sourceElement");
+
+ QVERIFY(loader != 0);
+ QVERIFY(sourceElement != 0);
+
+ QCOMPARE(rootItem->width(), 300.0);
+ QCOMPARE(rootItem->height(), 200.0);
+
+ QCOMPARE(loader->width(), 300.0);
+ QCOMPARE(loader->height(), 200.0);
+
+ QCOMPARE(sourceElement->width(), 300.0);
+ QCOMPARE(sourceElement->height(), 200.0);
+}
+
+void tst_QSGLoader::sizeLoaderToItem()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("/SizeToItem.qml"));
+ QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
+ QVERIFY(loader != 0);
+ QCOMPARE(loader->width(), 120.0);
+ QCOMPARE(loader->height(), 60.0);
+
+ // Check resize
+ QSGItem *rect = qobject_cast<QSGItem*>(loader->item());
+ QVERIFY(rect);
+ rect->setWidth(150);
+ rect->setHeight(45);
+ QCOMPARE(loader->width(), 150.0);
+ QCOMPARE(loader->height(), 45.0);
+
+ // Check explicit width
+ loader->setWidth(200.0);
+ QCOMPARE(loader->width(), 200.0);
+ QCOMPARE(rect->width(), 200.0);
+ rect->setWidth(100.0); // when rect changes ...
+ QCOMPARE(rect->width(), 100.0); // ... it changes
+ QCOMPARE(loader->width(), 200.0); // ... but loader stays the same
+
+ // Check explicit height
+ loader->setHeight(200.0);
+ QCOMPARE(loader->height(), 200.0);
+ QCOMPARE(rect->height(), 200.0);
+ rect->setHeight(100.0); // when rect changes ...
+ QCOMPARE(rect->height(), 100.0); // ... it changes
+ QCOMPARE(loader->height(), 200.0); // ... but loader stays the same
+
+ // Switch mode
+ loader->setWidth(180);
+ loader->setHeight(30);
+ QCOMPARE(rect->width(), 180.0);
+ QCOMPARE(rect->height(), 30.0);
+
+ delete loader;
+}
+
+void tst_QSGLoader::sizeItemToLoader()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("/SizeToLoader.qml"));
+ QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
+ QVERIFY(loader != 0);
+ QCOMPARE(loader->width(), 200.0);
+ QCOMPARE(loader->height(), 80.0);
+
+ QSGItem *rect = qobject_cast<QSGItem*>(loader->item());
+ QVERIFY(rect);
+ QCOMPARE(rect->width(), 200.0);
+ QCOMPARE(rect->height(), 80.0);
+
+ // Check resize
+ loader->setWidth(180);
+ loader->setHeight(30);
+ QCOMPARE(rect->width(), 180.0);
+ QCOMPARE(rect->height(), 30.0);
+
+ // Switch mode
+ loader->resetWidth(); // reset explicit size
+ loader->resetHeight();
+ rect->setWidth(160);
+ rect->setHeight(45);
+ QCOMPARE(loader->width(), 160.0);
+ QCOMPARE(loader->height(), 45.0);
+
+ delete loader;
+}
+
+void tst_QSGLoader::noResize()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("/NoResize.qml"));
+ QSGItem* item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item != 0);
+ QCOMPARE(item->width(), 200.0);
+ QCOMPARE(item->height(), 80.0);
+
+ delete item;
+}
+
+void tst_QSGLoader::networkRequestUrl()
+{
+ TestHTTPServer server(SERVER_PORT);
+ QVERIFY(server.isValid());
+ server.serveDirectory(SRCDIR "/data");
+
+ QDeclarativeComponent component(&engine);
+ component.setData(QByteArray("import QtQuick 2.0\nLoader { property int signalCount : 0; source: \"http://127.0.0.1:14450/Rect120x60.qml\"; onLoaded: signalCount += 1 }"), QUrl::fromLocalFile(SRCDIR "/dummy.qml"));
+ if (component.isError())
+ qDebug() << component.errors();
+ QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
+ QVERIFY(loader != 0);
+
+ QTRY_VERIFY(loader->status() == QSGLoader::Ready);
+
+ QVERIFY(loader->item());
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(loader->property("signalCount").toInt(), 1);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
+
+ delete loader;
+}
+
+/* XXX Component waits until all dependencies are loaded. Is this actually possible?
+void tst_QSGLoader::networkComponent()
+{
+ TestHTTPServer server(SERVER_PORT);
+ QVERIFY(server.isValid());
+ server.serveDirectory("slowdata", TestHTTPServer::Delay);
+
+ QDeclarativeComponent component(&engine);
+ component.setData(QByteArray(
+ "import QtQuick 2.0\n"
+ "import \"http://127.0.0.1:14450/\" as NW\n"
+ "Item {\n"
+ " Component { id: comp; NW.SlowRect {} }\n"
+ " Loader { sourceComponent: comp } }")
+ , TEST_FILE(""));
+
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+
+ QSGLoader *loader = qobject_cast<QSGLoader*>(item->QSGItem::children().at(1));
+ QVERIFY(loader);
+ QTRY_VERIFY(loader->status() == QSGLoader::Ready);
+
+ QVERIFY(loader->item());
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(loader->status(), QSGLoader::Ready);
+ QCOMPARE(static_cast<QSGItem*>(loader)->children().count(), 1);
+
+ delete loader;
+}
+*/
+
+void tst_QSGLoader::failNetworkRequest()
+{
+ TestHTTPServer server(SERVER_PORT);
+ QVERIFY(server.isValid());
+ server.serveDirectory(SRCDIR "/data");
+
+ QTest::ignoreMessage(QtWarningMsg, "http://127.0.0.1:14450/IDontExist.qml: File not found");
+
+ QDeclarativeComponent component(&engine);
+ component.setData(QByteArray("import QtQuick 2.0\nLoader { property int did_load: 123; source: \"http://127.0.0.1:14450/IDontExist.qml\"; onLoaded: did_load=456 }"), QUrl::fromLocalFile("http://127.0.0.1:14450/dummy.qml"));
+ QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
+ QVERIFY(loader != 0);
+
+ QTRY_VERIFY(loader->status() == QSGLoader::Error);
+
+ QVERIFY(loader->item() == 0);
+ QCOMPARE(loader->progress(), 0.0);
+ QCOMPARE(loader->property("did_load").toInt(), 123);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 0);
+
+ delete loader;
+}
+
+// QTBUG-9241
+void tst_QSGLoader::deleteComponentCrash()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("crash.qml"));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+
+ item->metaObject()->invokeMethod(item, "setLoaderSource");
+
+ QSGLoader *loader = qobject_cast<QSGLoader*>(item->QSGItem::childItems().at(0));
+ QVERIFY(loader);
+ QVERIFY(loader->item());
+ QCOMPARE(loader->item()->objectName(), QLatin1String("blue"));
+ QCOMPARE(loader->progress(), 1.0);
+ QCOMPARE(loader->status(), QSGLoader::Ready);
+ QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
+ QVERIFY(loader->source() == QUrl::fromLocalFile(SRCDIR "/data/BlueRect.qml"));
+
+ delete item;
+}
+
+void tst_QSGLoader::nonItem()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("nonItem.qml"));
+ QString err = QUrl::fromLocalFile(SRCDIR).toString() + "/data/nonItem.qml:3:1: QML Loader: Loader does not support loading non-visual elements.";
+
+ QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
+ QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
+ QVERIFY(loader);
+ QVERIFY(loader->item() == 0);
+
+ delete loader;
+}
+
+void tst_QSGLoader::vmeErrors()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("vmeErrors.qml"));
+ QString err = QUrl::fromLocalFile(SRCDIR).toString() + "/data/VmeError.qml:6: Cannot assign object type QObject with no default method";
+ QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
+ QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
+ QVERIFY(loader);
+ QVERIFY(loader->item() == 0);
+
+ delete loader;
+}
+
+// QTBUG-13481
+void tst_QSGLoader::creationContext()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("creationContext.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test").toBool(), true);
+
+ delete o;
+}
+
+void tst_QSGLoader::QTBUG_16928()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("QTBUG_16928.qml"));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+
+ QCOMPARE(item->width(), 250.);
+ QCOMPARE(item->height(), 250.);
+
+ delete item;
+}
+
+void tst_QSGLoader::implicitSize()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("implicitSize.qml"));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+
+ QCOMPARE(item->width(), 150.);
+ QCOMPARE(item->height(), 150.);
+
+ QCOMPARE(item->property("implHeight").toReal(), 100.);
+ QCOMPARE(item->property("implWidth").toReal(), 100.);
+
+ delete item;
+}
+
+void tst_QSGLoader::QTBUG_17114()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("QTBUG_17114.qml"));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+
+ QCOMPARE(item->property("loaderWidth").toReal(), 32.);
+ QCOMPARE(item->property("loaderHeight").toReal(), 32.);
+
+ delete item;
+}
+
+QTEST_MAIN(tst_QSGLoader)
+
+#include "tst_qsgloader.moc"
diff --git a/tests/auto/declarative/qsgmousearea/data/clickThrough.qml b/tests/auto/declarative/qsgmousearea/data/clickThrough.qml
new file mode 100644
index 0000000000..0d954f8511
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/clickThrough.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Item{
+ width: 200
+ height: 200
+ property int doubleClicks: 0
+ property int clicks: 0
+ property int pressAndHolds: 0
+ property int presses: 0
+ MouseArea{
+ z: 0
+ anchors.fill: parent
+ onPressed: presses++
+ onClicked: clicks++
+ onPressAndHold: pressAndHolds++
+ onDoubleClicked: doubleClicks++
+ }
+ MouseArea{
+ z: 1
+ enabled: true
+ anchors.fill: parent
+ }
+}
diff --git a/tests/auto/declarative/qsgmousearea/data/clickThrough2.qml b/tests/auto/declarative/qsgmousearea/data/clickThrough2.qml
new file mode 100644
index 0000000000..bc73a1bf8a
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/clickThrough2.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.0
+
+Item{
+ width: 300
+ height: 300
+ property int doubleClicks: 0
+ property int clicks: 0
+ property int pressAndHolds: 0
+ property int presses: 0
+ property bool letThrough: false
+ Rectangle{
+ z: 0
+ color: "lightsteelblue"
+ width: 150
+ height: 150
+ MouseArea{
+ anchors.fill: parent
+ onPressed: presses++
+ onClicked: clicks++
+ onPressAndHold: pressAndHolds++
+ onDoubleClicked: doubleClicks++
+ }
+ }
+ MouseArea{
+ z: 1
+ enabled: true
+ anchors.fill: parent
+ onClicked: mouse.accepted = !letThrough;
+ onDoubleClicked: mouse.accepted = !letThrough;
+ onPressAndHold: mouse.accepted = !letThrough;
+ }
+}
diff --git a/tests/auto/declarative/qsgmousearea/data/clickandhold.qml b/tests/auto/declarative/qsgmousearea/data/clickandhold.qml
new file mode 100644
index 0000000000..5e4e48f6db
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/clickandhold.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property bool clicked: false
+ property bool held: false
+
+ MouseArea {
+ width: 200; height: 200
+ onClicked: { root.clicked = true }
+ onPressAndHold: { root.held = true }
+ }
+}
diff --git a/tests/auto/declarative/qsgmousearea/data/clicktwice.qml b/tests/auto/declarative/qsgmousearea/data/clicktwice.qml
new file mode 100644
index 0000000000..002d1b9047
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/clicktwice.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int clicked: 0
+ property int pressed: 0
+ property int released: 0
+
+ MouseArea {
+ width: 200; height: 200
+ onPressed: { root.pressed++ }
+ onClicked: { root.clicked++ }
+ onReleased: { root.released++ }
+ }
+}
+
diff --git a/tests/auto/declarative/qsgmousearea/data/doubleclick.qml b/tests/auto/declarative/qsgmousearea/data/doubleclick.qml
new file mode 100644
index 0000000000..1030d0c33e
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/doubleclick.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int clicked: 0
+ property int doubleClicked: 0
+ property int released: 0
+
+ MouseArea {
+ width: 200; height: 200
+ onClicked: { root.clicked++ }
+ onDoubleClicked: { root.doubleClicked++ }
+ onReleased: { root.released++ }
+ }
+}
+
diff --git a/tests/auto/declarative/qsgmousearea/data/dragging.qml b/tests/auto/declarative/qsgmousearea/data/dragging.qml
new file mode 100644
index 0000000000..d9b6ac4083
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/dragging.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+Rectangle {
+ id: whiteRect
+ width: 200
+ height: 200
+ color: "white"
+ Rectangle {
+ id: blackRect
+ objectName: "blackrect"
+ color: "black"
+ y: 50
+ x: 50
+ width: 100
+ height: 100
+ opacity: (whiteRect.width-blackRect.x+whiteRect.height-blackRect.y-199)/200
+ Text { text: blackRect.opacity}
+ MouseArea {
+ objectName: "mouseregion"
+ anchors.fill: parent
+ drag.target: blackRect
+ drag.axis: Drag.XandYAxis
+ drag.minimumX: 0
+ drag.maximumX: whiteRect.width-blackRect.width
+ drag.minimumY: 0
+ drag.maximumY: whiteRect.height-blackRect.height
+ }
+ }
+ }
diff --git a/tests/auto/declarative/qsgmousearea/data/dragproperties.qml b/tests/auto/declarative/qsgmousearea/data/dragproperties.qml
new file mode 100644
index 0000000000..421dfe26b7
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/dragproperties.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+Rectangle {
+ id: whiteRect
+ width: 200
+ height: 200
+ color: "white"
+ Rectangle {
+ id: blackRect
+ objectName: "blackrect"
+ color: "black"
+ y: 50
+ x: 50
+ width: 100
+ height: 100
+ opacity: (whiteRect.width-blackRect.x+whiteRect.height-blackRect.y-199)/200
+ Text { text: blackRect.opacity}
+ MouseArea {
+ objectName: "mouseregion"
+ anchors.fill: parent
+ drag.target: blackRect
+ drag.axis: Drag.XandYAxis
+ drag.minimumX: 0
+ drag.maximumX: whiteRect.width-blackRect.width
+ drag.minimumY: 0
+ drag.maximumY: whiteRect.height-blackRect.height
+ }
+ }
+ }
diff --git a/tests/auto/declarative/qsgmousearea/data/dragreset.qml b/tests/auto/declarative/qsgmousearea/data/dragreset.qml
new file mode 100644
index 0000000000..d7949f9139
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/dragreset.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+Rectangle {
+ id: whiteRect
+ width: 200
+ height: 200
+ color: "white"
+ Rectangle {
+ id: blackRect
+ objectName: "blackrect"
+ color: "black"
+ y: 50
+ x: 50
+ width: 100
+ height: 100
+ opacity: (whiteRect.width-blackRect.x+whiteRect.height-blackRect.y-199)/200
+ Text { text: blackRect.opacity}
+ MouseArea {
+ objectName: "mouseregion"
+ anchors.fill: parent
+ drag.target: haveTarget ? blackRect : undefined
+ drag.axis: Drag.XandYAxis
+ drag.minimumX: 0
+ drag.maximumX: whiteRect.width-blackRect.width
+ drag.minimumY: 0
+ drag.maximumY: whiteRect.height-blackRect.height
+ }
+ }
+ }
diff --git a/tests/auto/declarative/qsgmousearea/data/hoverPosition.qml b/tests/auto/declarative/qsgmousearea/data/hoverPosition.qml
new file mode 100644
index 0000000000..834f91ff29
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/hoverPosition.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 400; height: 400;
+
+ property real mouseX: mousetracker.mouseX
+ property real mouseY: mousetracker.mouseY
+
+ Rectangle {
+ width: 100; height: 100;
+ MouseArea {
+ id: mousetracker;
+ anchors.fill: parent;
+ hoverEnabled: true
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgmousearea/data/pressedOrdering.qml b/tests/auto/declarative/qsgmousearea/data/pressedOrdering.qml
new file mode 100644
index 0000000000..7aa3098100
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/pressedOrdering.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property string value: "base"
+
+ MouseArea {
+ id: mouseArea
+ width: 200; height: 200
+ onClicked: toggleState.state = "toggled"
+ }
+
+ StateGroup {
+ states: State {
+ name: "pressed"
+ when: mouseArea.pressed
+ PropertyChanges { target: root; value: "pressed" }
+ }
+ }
+
+ StateGroup {
+ id: toggleState
+ states: State {
+ name: "toggled"
+ PropertyChanges { target: root; value: "toggled" }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgmousearea/data/preventstealing.qml b/tests/auto/declarative/qsgmousearea/data/preventstealing.qml
new file mode 100644
index 0000000000..fb0d6955c1
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/preventstealing.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Flickable {
+ property bool stealing: true
+ width: 200
+ height: 200
+ contentWidth: 400
+ contentHeight: 400
+ Rectangle {
+ color: "black"
+ width: 400
+ height: 400
+ Rectangle {
+ x: 50; y: 50
+ width: 100; height: 100
+ color: "steelblue"
+ MouseArea {
+ objectName: "mousearea"
+ anchors.fill: parent
+ preventStealing: stealing
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgmousearea/data/rejectEvent.qml b/tests/auto/declarative/qsgmousearea/data/rejectEvent.qml
new file mode 100644
index 0000000000..816fc76fac
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/rejectEvent.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ color: "#ffffff"
+ width: 320; height: 240
+ property bool mr1_pressed: false
+ property bool mr1_released: false
+ property bool mr1_canceled: false
+ property bool mr2_pressed: false
+ property bool mr2_released: false
+ property bool mr2_canceled: false
+
+ MouseArea {
+ id: mouseRegion1
+ anchors.fill: parent
+ onPressed: { root.mr1_pressed = true }
+ onReleased: { root.mr1_released = true }
+ onCanceled: { root.mr1_canceled = true }
+ }
+ MouseArea {
+ id: mouseRegion2
+ width: 120; height: 120
+ onPressed: { root.mr2_pressed = true; mouse.accepted = false }
+ onReleased: { root.mr2_released = true }
+ onCanceled: { root.mr2_canceled = true }
+ }
+}
diff --git a/tests/auto/declarative/qsgmousearea/data/updateMousePosOnClick.qml b/tests/auto/declarative/qsgmousearea/data/updateMousePosOnClick.qml
new file mode 100644
index 0000000000..7377a2e86c
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/updateMousePosOnClick.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+
+Rectangle {
+ color: "#ffffff"
+ width: 320; height: 240
+ MouseArea {
+ id: mouseRegion
+ objectName: "mouseregion"
+ anchors.fill: parent
+ Rectangle {
+ id: ball
+ objectName: "ball"
+ width: 20; height: 20
+ radius: 10
+ color: "#0000ff"
+ x: { mouseRegion.mouseX }
+ y: mouseRegion.mouseY
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgmousearea/data/updateMousePosOnResize.qml b/tests/auto/declarative/qsgmousearea/data/updateMousePosOnResize.qml
new file mode 100644
index 0000000000..ad52ef3820
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/data/updateMousePosOnResize.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.0
+
+Rectangle {
+ color: "#ffffff"
+ width: 320; height: 240
+ Rectangle {
+ id: brother
+ objectName: "brother"
+ color: "lightgreen"
+ x: 200; y: 100
+ width: 120; height: 120
+ }
+ MouseArea {
+ id: mouseRegion
+ objectName: "mouseregion"
+
+ property int x1
+ property int y1
+ property int x2
+ property int y2
+ property bool emitPositionChanged: false
+ property bool mouseMatchesPos: true
+
+ anchors.fill: brother
+ onPressed: {
+ if (mouse.x != mouseX || mouse.y != mouseY)
+ mouseMatchesPos = false
+ x1 = mouseX; y1 = mouseY
+ anchors.fill = parent
+ }
+ onPositionChanged: { emitPositionChanged = true }
+ onMousePositionChanged: {
+ if (mouse.x != mouseX || mouse.y != mouseY)
+ mouseMatchesPos = false
+ x2 = mouseX; y2 = mouseY
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgmousearea/qsgmousearea.pro b/tests/auto/declarative/qsgmousearea/qsgmousearea.pro
new file mode 100644
index 0000000000..7d47ce3ae3
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/qsgmousearea.pro
@@ -0,0 +1,17 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui network
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/testhttpserver.h
+SOURCES += tst_qsgmousearea.cpp ../shared/testhttpserver.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgmousearea/tst_qsgmousearea.cpp b/tests/auto/declarative/qsgmousearea/tst_qsgmousearea.cpp
new file mode 100644
index 0000000000..857f888c29
--- /dev/null
+++ b/tests/auto/declarative/qsgmousearea/tst_qsgmousearea.cpp
@@ -0,0 +1,705 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtTest/QSignalSpy>
+#include <private/qsgmousearea_p.h>
+#include <private/qsgrectangle_p.h>
+#include <private/qsgflickable_p.h>
+#include <QtDeclarative/qsgview.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_QSGMouseArea: public QObject
+{
+ Q_OBJECT
+private slots:
+ void dragProperties();
+ void resetDrag();
+ void dragging();
+ void updateMouseAreaPosOnClick();
+ void updateMouseAreaPosOnResize();
+ void noOnClickedWithPressAndHold();
+ void onMousePressRejected();
+ void doubleClick();
+ void clickTwice();
+ void pressedOrdering();
+ void preventStealing();
+ void clickThrough();
+ void testQtQuick11Attributes();
+ void testQtQuick11Attributes_data();
+ void hoverPosition();
+
+private:
+ QSGView *createView();
+};
+
+void tst_QSGMouseArea::dragProperties()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/dragproperties.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGMouseArea *mouseRegion = canvas->rootObject()->findChild<QSGMouseArea*>("mouseregion");
+ QSGDrag *drag = mouseRegion->drag();
+ QVERIFY(mouseRegion != 0);
+ QVERIFY(drag != 0);
+
+ // target
+ QSGItem *blackRect = canvas->rootObject()->findChild<QSGItem*>("blackrect");
+ QVERIFY(blackRect != 0);
+ QVERIFY(blackRect == drag->target());
+ QSGItem *rootItem = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(rootItem != 0);
+ QSignalSpy targetSpy(drag, SIGNAL(targetChanged()));
+ drag->setTarget(rootItem);
+ QCOMPARE(targetSpy.count(),1);
+ drag->setTarget(rootItem);
+ QCOMPARE(targetSpy.count(),1);
+
+ // axis
+ QCOMPARE(drag->axis(), QSGDrag::XandYAxis);
+ QSignalSpy axisSpy(drag, SIGNAL(axisChanged()));
+ drag->setAxis(QSGDrag::XAxis);
+ QCOMPARE(drag->axis(), QSGDrag::XAxis);
+ QCOMPARE(axisSpy.count(),1);
+ drag->setAxis(QSGDrag::XAxis);
+ QCOMPARE(axisSpy.count(),1);
+
+ // minimum and maximum properties
+ QSignalSpy xminSpy(drag, SIGNAL(minimumXChanged()));
+ QSignalSpy xmaxSpy(drag, SIGNAL(maximumXChanged()));
+ QSignalSpy yminSpy(drag, SIGNAL(minimumYChanged()));
+ QSignalSpy ymaxSpy(drag, SIGNAL(maximumYChanged()));
+
+ QCOMPARE(drag->xmin(), 0.0);
+ QCOMPARE(drag->xmax(), rootItem->width()-blackRect->width());
+ QCOMPARE(drag->ymin(), 0.0);
+ QCOMPARE(drag->ymax(), rootItem->height()-blackRect->height());
+
+ drag->setXmin(10);
+ drag->setXmax(10);
+ drag->setYmin(10);
+ drag->setYmax(10);
+
+ QCOMPARE(drag->xmin(), 10.0);
+ QCOMPARE(drag->xmax(), 10.0);
+ QCOMPARE(drag->ymin(), 10.0);
+ QCOMPARE(drag->ymax(), 10.0);
+
+ QCOMPARE(xminSpy.count(),1);
+ QCOMPARE(xmaxSpy.count(),1);
+ QCOMPARE(yminSpy.count(),1);
+ QCOMPARE(ymaxSpy.count(),1);
+
+ drag->setXmin(10);
+ drag->setXmax(10);
+ drag->setYmin(10);
+ drag->setYmax(10);
+
+ QCOMPARE(xminSpy.count(),1);
+ QCOMPARE(xmaxSpy.count(),1);
+ QCOMPARE(yminSpy.count(),1);
+ QCOMPARE(ymaxSpy.count(),1);
+
+ // filterChildren
+ QSignalSpy filterChildrenSpy(drag, SIGNAL(filterChildrenChanged()));
+
+ drag->setFilterChildren(true);
+
+ QVERIFY(drag->filterChildren());
+ QCOMPARE(filterChildrenSpy.count(), 1);
+
+ drag->setFilterChildren(true);
+ QCOMPARE(filterChildrenSpy.count(), 1);
+
+ delete canvas;
+}
+
+void tst_QSGMouseArea::resetDrag()
+{
+ QSGView *canvas = createView();
+
+ canvas->rootContext()->setContextProperty("haveTarget", QVariant(true));
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/dragreset.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGMouseArea *mouseRegion = canvas->rootObject()->findChild<QSGMouseArea*>("mouseregion");
+ QSGDrag *drag = mouseRegion->drag();
+ QVERIFY(mouseRegion != 0);
+ QVERIFY(drag != 0);
+
+ // target
+ QSGItem *blackRect = canvas->rootObject()->findChild<QSGItem*>("blackrect");
+ QVERIFY(blackRect != 0);
+ QVERIFY(blackRect == drag->target());
+ QSGItem *rootItem = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(rootItem != 0);
+ QSignalSpy targetSpy(drag, SIGNAL(targetChanged()));
+ QVERIFY(drag->target() != 0);
+ canvas->rootContext()->setContextProperty("haveTarget", QVariant(false));
+ QCOMPARE(targetSpy.count(),1);
+ QVERIFY(drag->target() == 0);
+
+ delete canvas;
+}
+
+
+void tst_QSGMouseArea::dragging()
+{
+ QSGView *canvas = createView();
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/dragging.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGMouseArea *mouseRegion = canvas->rootObject()->findChild<QSGMouseArea*>("mouseregion");
+ QSGDrag *drag = mouseRegion->drag();
+ QVERIFY(mouseRegion != 0);
+ QVERIFY(drag != 0);
+
+ // target
+ QSGItem *blackRect = canvas->rootObject()->findChild<QSGItem*>("blackrect");
+ QVERIFY(blackRect != 0);
+ QVERIFY(blackRect == drag->target());
+
+ QVERIFY(!drag->active());
+
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ QVERIFY(!drag->active());
+ QCOMPARE(blackRect->x(), 50.0);
+ QCOMPARE(blackRect->y(), 50.0);
+
+ // First move event triggers drag, second is acted upon.
+ // This is due to possibility of higher stacked area taking precedence.
+ QMouseEvent moveEvent(QEvent::MouseMove, QPoint(106, 106), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &moveEvent);
+ moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(110, 110), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &moveEvent);
+
+ QVERIFY(drag->active());
+ QCOMPARE(blackRect->x(), 60.0);
+ QCOMPARE(blackRect->y(), 60.0);
+
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(110, 110), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QVERIFY(!drag->active());
+ QCOMPARE(blackRect->x(), 60.0);
+ QCOMPARE(blackRect->y(), 60.0);
+
+ delete canvas;
+}
+
+QSGView *tst_QSGMouseArea::createView()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ return canvas;
+}
+
+void tst_QSGMouseArea::updateMouseAreaPosOnClick()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/updateMousePosOnClick.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGMouseArea *mouseRegion = canvas->rootObject()->findChild<QSGMouseArea*>("mouseregion");
+ QVERIFY(mouseRegion != 0);
+
+ QSGRectangle *rect = canvas->rootObject()->findChild<QSGRectangle*>("ball");
+ QVERIFY(rect != 0);
+
+ QCOMPARE(mouseRegion->mouseX(), rect->x());
+ QCOMPARE(mouseRegion->mouseY(), rect->y());
+
+ QMouseEvent event(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &event);
+
+ QCOMPARE(mouseRegion->mouseX(), 100.0);
+ QCOMPARE(mouseRegion->mouseY(), 100.0);
+
+ QCOMPARE(mouseRegion->mouseX(), rect->x());
+ QCOMPARE(mouseRegion->mouseY(), rect->y());
+
+ delete canvas;
+}
+
+void tst_QSGMouseArea::updateMouseAreaPosOnResize()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/updateMousePosOnResize.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGMouseArea *mouseRegion = canvas->rootObject()->findChild<QSGMouseArea*>("mouseregion");
+ QVERIFY(mouseRegion != 0);
+
+ QSGRectangle *rect = canvas->rootObject()->findChild<QSGRectangle*>("brother");
+ QVERIFY(rect != 0);
+
+ QCOMPARE(mouseRegion->mouseX(), 0.0);
+ QCOMPARE(mouseRegion->mouseY(), 0.0);
+
+ QMouseEvent event(QEvent::MouseButtonPress, rect->pos().toPoint(), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &event);
+
+ QVERIFY(!mouseRegion->property("emitPositionChanged").toBool());
+ QVERIFY(mouseRegion->property("mouseMatchesPos").toBool());
+
+ QCOMPARE(mouseRegion->property("x1").toInt(), 0);
+ QCOMPARE(mouseRegion->property("y1").toInt(), 0);
+
+ // XXX: is it on purpose that mouseX is real and mouse.x is int?
+ QCOMPARE(mouseRegion->property("x2").toInt(), (int) rect->x());
+ QCOMPARE(mouseRegion->property("y2").toInt(), (int) rect->y());
+
+ QCOMPARE(mouseRegion->mouseX(), rect->x());
+ QCOMPARE(mouseRegion->mouseY(), rect->y());
+
+ delete canvas;
+}
+
+void tst_QSGMouseArea::noOnClickedWithPressAndHold()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/clickandhold.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ QVERIFY(!canvas->rootObject()->property("clicked").toBool());
+ QVERIFY(!canvas->rootObject()->property("held").toBool());
+
+ QTest::qWait(1000);
+
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QVERIFY(!canvas->rootObject()->property("clicked").toBool());
+ QVERIFY(canvas->rootObject()->property("held").toBool());
+
+ delete canvas;
+}
+
+void tst_QSGMouseArea::onMousePressRejected()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/rejectEvent.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+ QVERIFY(canvas->rootObject()->property("enabled").toBool());
+
+ QVERIFY(!canvas->rootObject()->property("mr1_pressed").toBool());
+ QVERIFY(!canvas->rootObject()->property("mr1_released").toBool());
+ QVERIFY(!canvas->rootObject()->property("mr1_canceled").toBool());
+ QVERIFY(!canvas->rootObject()->property("mr2_pressed").toBool());
+ QVERIFY(!canvas->rootObject()->property("mr2_released").toBool());
+ QVERIFY(!canvas->rootObject()->property("mr2_canceled").toBool());
+
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ QVERIFY(canvas->rootObject()->property("mr1_pressed").toBool());
+ QVERIFY(!canvas->rootObject()->property("mr1_released").toBool());
+ QVERIFY(!canvas->rootObject()->property("mr1_canceled").toBool());
+ QVERIFY(canvas->rootObject()->property("mr2_pressed").toBool());
+ QVERIFY(!canvas->rootObject()->property("mr2_released").toBool());
+ QVERIFY(canvas->rootObject()->property("mr2_canceled").toBool());
+
+ QTest::qWait(200);
+
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QVERIFY(canvas->rootObject()->property("mr1_released").toBool());
+ QVERIFY(!canvas->rootObject()->property("mr1_canceled").toBool());
+ QVERIFY(!canvas->rootObject()->property("mr2_released").toBool());
+
+ delete canvas;
+}
+
+void tst_QSGMouseArea::doubleClick()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/doubleclick.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("released").toInt(), 1);
+
+ pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("clicked").toInt(), 1);
+ QCOMPARE(canvas->rootObject()->property("doubleClicked").toInt(), 1);
+ QCOMPARE(canvas->rootObject()->property("released").toInt(), 2);
+
+ delete canvas;
+}
+
+// QTBUG-14832
+void tst_QSGMouseArea::clickTwice()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/clicktwice.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("pressed").toInt(), 1);
+ QCOMPARE(canvas->rootObject()->property("released").toInt(), 1);
+ QCOMPARE(canvas->rootObject()->property("clicked").toInt(), 1);
+
+ pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ QApplication::sendEvent(canvas, &pressEvent);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("pressed").toInt(), 2);
+ QCOMPARE(canvas->rootObject()->property("released").toInt(), 2);
+ QCOMPARE(canvas->rootObject()->property("clicked").toInt(), 2);
+
+ delete canvas;
+}
+
+void tst_QSGMouseArea::pressedOrdering()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pressedOrdering.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QCOMPARE(canvas->rootObject()->property("value").toString(), QLatin1String("base"));
+
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ QCOMPARE(canvas->rootObject()->property("value").toString(), QLatin1String("pressed"));
+
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("value").toString(), QLatin1String("toggled"));
+
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ QCOMPARE(canvas->rootObject()->property("value").toString(), QLatin1String("pressed"));
+
+ delete canvas;
+}
+
+void tst_QSGMouseArea::preventStealing()
+{
+ QSGView *canvas = createView();
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/preventstealing.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGFlickable *flickable = qobject_cast<QSGFlickable*>(canvas->rootObject());
+ QVERIFY(flickable != 0);
+
+ QSGMouseArea *mouseArea = canvas->rootObject()->findChild<QSGMouseArea*>("mousearea");
+ QVERIFY(mouseArea != 0);
+
+ QSignalSpy mousePositionSpy(mouseArea, SIGNAL(positionChanged(QSGMouseEvent*)));
+
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(80, 80));
+
+ // Without preventStealing, mouse movement over MouseArea would
+ // cause the Flickable to steal mouse and trigger content movement.
+
+ QMouseEvent moveEvent(QEvent::MouseMove, QPoint(70, 70), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &moveEvent);
+
+ moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(60, 60), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &moveEvent);
+
+ moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(50, 50), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &moveEvent);
+
+ // We should have received all three move events
+ QCOMPARE(mousePositionSpy.count(), 3);
+ QVERIFY(mouseArea->pressed());
+
+ // Flickable content should not have moved.
+ QCOMPARE(flickable->contentX(), 0.);
+ QCOMPARE(flickable->contentY(), 0.);
+
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 50));
+
+ // Now allow stealing and confirm Flickable does its thing.
+ canvas->rootObject()->setProperty("stealing", false);
+
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(80, 80));
+
+ // Without preventStealing, mouse movement over MouseArea would
+ // cause the Flickable to steal mouse and trigger content movement.
+ moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(70, 70), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &moveEvent);
+
+ moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(60, 60), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &moveEvent);
+
+ moveEvent = QMouseEvent(QEvent::MouseMove, QPoint(50, 50), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &moveEvent);
+
+ // We should only have received the first move event
+ QCOMPARE(mousePositionSpy.count(), 4);
+ // Our press should be taken away
+ QVERIFY(!mouseArea->pressed());
+
+ // Flickable content should have moved.
+ QCOMPARE(flickable->contentX(), 10.);
+ QCOMPARE(flickable->contentY(), 10.);
+
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 50));
+
+ delete canvas;
+}
+
+void tst_QSGMouseArea::clickThrough()
+{
+ //With no handlers defined click, doubleClick and PressAndHold should propagate to those with handlers
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/clickThrough.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 1);
+
+ QApplication::sendEvent(canvas, &pressEvent);
+ QTest::qWait(1000);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 1);
+ QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 1);
+
+ QApplication::sendEvent(canvas, &pressEvent);
+ QApplication::sendEvent(canvas, &releaseEvent);
+ pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+
+ QApplication::sendEvent(canvas, &pressEvent);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 2);
+ QCOMPARE(canvas->rootObject()->property("doubleClicks").toInt(), 1);
+ QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 1);
+
+ delete canvas;
+
+ //With handlers defined click, doubleClick and PressAndHold should propagate only when explicitly ignored
+ canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/clickThrough2.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ pressEvent = QMouseEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ releaseEvent = QMouseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 0);
+
+ QApplication::sendEvent(canvas, &pressEvent);
+ QTest::qWait(1000);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 0);
+
+ QApplication::sendEvent(canvas, &pressEvent);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("doubleClicks").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 0);
+
+ canvas->rootObject()->setProperty("letThrough", QVariant(true));
+
+ pressEvent = QMouseEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &pressEvent);
+
+ releaseEvent = QMouseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 1);
+
+ QApplication::sendEvent(canvas, &pressEvent);
+ QTest::qWait(1000);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 1);
+ QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 1);
+
+ QApplication::sendEvent(canvas, &pressEvent);
+ QApplication::sendEvent(canvas, &releaseEvent);
+ pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
+
+ QApplication::sendEvent(canvas, &pressEvent);
+ QApplication::sendEvent(canvas, &releaseEvent);
+
+ QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 2);
+ QCOMPARE(canvas->rootObject()->property("doubleClicks").toInt(), 1);
+ QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 1);
+
+ delete canvas;
+}
+
+void tst_QSGMouseArea::testQtQuick11Attributes()
+{
+ QFETCH(QString, code);
+ QFETCH(QString, warning);
+ QFETCH(QString, error);
+
+ QDeclarativeEngine engine;
+ QObject *obj;
+
+ QDeclarativeComponent valid(&engine);
+ valid.setData("import QtQuick 1.1; MouseArea { " + code.toUtf8() + " }", QUrl(""));
+ obj = valid.create();
+ QVERIFY(obj);
+ QVERIFY(valid.errorString().isEmpty());
+ delete obj;
+
+ QDeclarativeComponent invalid(&engine);
+ invalid.setData("import QtQuick 1.0; MouseArea { " + code.toUtf8() + " }", QUrl(""));
+ QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
+ obj = invalid.create();
+ QCOMPARE(invalid.errorString(), error);
+ delete obj;
+}
+
+void tst_QSGMouseArea::testQtQuick11Attributes_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("preventStealing") << "preventStealing: true"
+ << "QDeclarativeComponent: Component is not ready"
+ << ":1 \"MouseArea.preventStealing\" is not available in QtQuick 1.0.\n";
+}
+
+void tst_QSGMouseArea::hoverPosition()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/hoverPosition.qml"));
+
+ QSGItem *root = canvas->rootObject();
+ QVERIFY(root != 0);
+
+ QCOMPARE(root->property("mouseX").toReal(), qreal(0));
+ QCOMPARE(root->property("mouseY").toReal(), qreal(0));
+
+ QMouseEvent moveEvent(QEvent::MouseMove, QPoint(10, 32), Qt::NoButton, Qt::NoButton, 0);
+ QApplication::sendEvent(canvas, &moveEvent);
+
+ QCOMPARE(root->property("mouseX").toReal(), qreal(10));
+ QCOMPARE(root->property("mouseY").toReal(), qreal(32));
+
+ delete canvas;
+}
+
+QTEST_MAIN(tst_QSGMouseArea)
+
+#include "tst_qsgmousearea.moc"
diff --git a/tests/auto/declarative/qsgpathview/data/closedPath.qml b/tests/auto/declarative/qsgpathview/data/closedPath.qml
new file mode 100644
index 0000000000..3ca34056c8
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/closedPath.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Path {
+ startY: 120
+ startX: 160
+ PathQuad {
+ y: 120
+ x: 80
+ controlY: 330
+ controlX: 100
+ }
+ PathLine {
+ y: 160
+ x: 20
+ }
+ PathCubic {
+ y: 120
+ x: 160
+ control1Y: 0
+ control1X: 100
+ control2Y: 000
+ control2X: 200
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/datamodel.qml b/tests/auto/declarative/qsgpathview/data/datamodel.qml
new file mode 100644
index 0000000000..839049f1fc
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/datamodel.qml
@@ -0,0 +1,37 @@
+import QtQuick 2.0
+
+PathView {
+ id: pathview
+ objectName: "pathview"
+ width: 240; height: 320
+ pathItemCount: testObject.pathItemCount
+
+ function checkProperties() {
+ testObject.error = false;
+ if (testObject.useModel && pathview.model != testData) {
+ console.log("model property incorrect");
+ testObject.error = true;
+ }
+ }
+
+ model: testObject.useModel ? testData : 0
+
+ delegate: Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ property bool onPath: PathView.onPath
+ width: 20; height: 20; color: name
+ Text {
+ objectName: "myText"
+ text: name
+ }
+ }
+ }
+
+ path: Path {
+ startX: 120; startY: 20;
+ PathLine { x: 120; y: 300 }
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/displaypath.qml b/tests/auto/declarative/qsgpathview/data/displaypath.qml
new file mode 100644
index 0000000000..af0f381fc4
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/displaypath.qml
@@ -0,0 +1,59 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: delegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 60
+ color: "white"
+ border.color: "black"
+ Text {
+ text: index
+ }
+ Text {
+ x: 20
+ id: displayText
+ objectName: "displayText"
+ text: display
+ }
+ }
+ }
+ ]
+ PathView {
+ id: view
+ objectName: "view"
+ width: 240
+ height: 320
+ model: testModel
+ delegate: delegate
+ path: Path {
+ startY: 120
+ startX: 160
+ PathQuad {
+ y: 120
+ x: 80
+ controlY: 330
+ controlX: 100
+ }
+ PathLine {
+ y: 160
+ x: 20
+ }
+ PathCubic {
+ y: 120
+ x: 160
+ control1Y: 0
+ control1X: 100
+ control2Y: 000
+ control2X: 200
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/dragpath.qml b/tests/auto/declarative/qsgpathview/data/dragpath.qml
new file mode 100644
index 0000000000..f9c6615b04
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/dragpath.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+PathView {
+ width: 400
+ height: 200
+ model: 100
+ pathItemCount: 20
+ path: Path {
+ startX: 0; startY: 100
+ PathLine { x: 400; y: 100 }
+ }
+ delegate: Rectangle { objectName: "wrapper"; height: 100; width: 2; color: PathView.isCurrentItem?"red" : "black" }
+ dragMargin: 100
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+ Text {
+ text: "current index: " + parent.currentIndex
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/emptymodel.qml b/tests/auto/declarative/qsgpathview/data/emptymodel.qml
new file mode 100644
index 0000000000..eb4d3006f4
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/emptymodel.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+PathView {
+ model: emptyModel
+}
diff --git a/tests/auto/declarative/qsgpathview/data/openPath.qml b/tests/auto/declarative/qsgpathview/data/openPath.qml
new file mode 100644
index 0000000000..1bd8375d9e
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/openPath.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+Path {
+ startY: 120
+ startX: 160
+ PathLine {
+ y: 160
+ x: 20
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/pathUpdate.qml b/tests/auto/declarative/qsgpathview/data/pathUpdate.qml
new file mode 100644
index 0000000000..e729291025
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/pathUpdate.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 400
+
+ PathView {
+ id: view
+ objectName: "pathView"
+ anchors.fill: parent
+ model: 10
+ delegate: Rectangle { objectName: "wrapper"; color: "green"; width: 100; height: 100 }
+ path: Path {
+ startX: view.width/2; startY: 0
+ PathLine { x: view.width/2; y: view.height }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/pathUpdateOnStartChanged.qml b/tests/auto/declarative/qsgpathview/data/pathUpdateOnStartChanged.qml
new file mode 100644
index 0000000000..89084b2a37
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/pathUpdateOnStartChanged.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 800
+ height: 480
+ color: "black"
+ resources: [
+ ListModel {
+ id: appModel
+ ListElement { color: "green" }
+ },
+ Component {
+ id: appDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ color: "green"
+ width: 100
+ height: 100
+ }
+ }
+ ]
+ PathView {
+ id: pathView
+ objectName: "pathView"
+ model: appModel
+ anchors.fill: parent
+
+ transformOrigin: "Top"
+ delegate: appDelegate
+ path: Path {
+ objectName: "path"
+ startX: pathView.width / 2 // startX: 400 <- this works as expected
+ startY: 300
+ PathLine { x: 400; y: 120 }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/pathtest.qml b/tests/auto/declarative/qsgpathview/data/pathtest.qml
new file mode 100644
index 0000000000..736d58d2a9
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/pathtest.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Path {
+ startX: 120; startY: 100
+
+ PathAttribute { name: "scale"; value: 1.0 }
+ PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 }
+ PathPercent { value: 0.3 }
+ PathLine { x: 120; y: 100 }
+ PathCubic {
+ x: 180; y: 0; control1X: -10; control1Y: 90
+ control2X: 210; control2Y: 90
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/pathview0.qml b/tests/auto/declarative/qsgpathview/data/pathview0.qml
new file mode 100644
index 0000000000..0204112812
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/pathview0.qml
@@ -0,0 +1,83 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ property int currentA: -1
+ property int currentB: -1
+ property real delegateWidth: 60
+ property real delegateHeight: 20
+ property real delegateScale: 1.0
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: delegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: root.delegateHeight
+ width: root.delegateWidth
+ scale: root.delegateScale
+ color: PathView.isCurrentItem ? "lightsteelblue" : "white"
+ border.color: "black"
+ Text {
+ text: index
+ }
+ Text {
+ x: 20
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ x: 40
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ PathView.onCurrentItemChanged: {
+ if (PathView.isCurrentItem) {
+ root.currentA = index;
+ root.currentB = wrapper.PathView.view.currentIndex;
+ }
+ }
+ }
+ }
+ ]
+ PathView {
+ id: view
+ objectName: "view"
+ width: 240
+ height: 320
+ model: testModel
+ delegate: delegate
+ highlight: Rectangle {
+ width: 60
+ height: 20
+ color: "yellow"
+ }
+ path: Path {
+ startY: 120
+ startX: 160
+ PathQuad {
+ y: 120
+ x: 80
+ controlY: 330
+ controlX: 100
+ }
+ PathLine {
+ y: 160
+ x: 20
+ }
+ PathCubic {
+ y: 120
+ x: 160
+ control1Y: 0
+ control1X: 100
+ control2Y: 000
+ control2X: 200
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/pathview1.qml b/tests/auto/declarative/qsgpathview/data/pathview1.qml
new file mode 100644
index 0000000000..53d375e596
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/pathview1.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.0
+
+PathView {
+}
diff --git a/tests/auto/declarative/qsgpathview/data/pathview2.qml b/tests/auto/declarative/qsgpathview/data/pathview2.qml
new file mode 100644
index 0000000000..1d279c42a0
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/pathview2.qml
@@ -0,0 +1,57 @@
+import QtQuick 2.0
+
+PathView {
+ id: photoPathView
+ y: 100; width: 800; height: 330; pathItemCount: 10; z: 1
+
+ path: Path {
+ startX: -50; startY: 40;
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: -45 }
+
+ PathCubic {
+ x: 400; y: 220
+ control1X: 140; control1Y: 40
+ control2X: 210; control2Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 1.2 }
+ PathAttribute { name: "angle"; value: 0 }
+
+ PathCubic {
+ x: 850; y: 40
+ control2X: 660; control2Y: 40
+ control1X: 590; control1Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: 45 }
+ }
+
+ model: ListModel {
+ id: rssModel
+ ListElement { lColor: "red" }
+ ListElement { lColor: "green" }
+ ListElement { lColor: "yellow" }
+ ListElement { lColor: "blue" }
+ ListElement { lColor: "purple" }
+ ListElement { lColor: "gray" }
+ ListElement { lColor: "brown" }
+ ListElement { lColor: "thistle" }
+ }
+
+ delegate: Component {
+ id: photoDelegate
+ Rectangle {
+ id: wrapper
+ width: 85; height: 85; color: lColor
+ scale: wrapper.PathView.scale
+
+ transform: Rotation {
+ id: itemRotation; origin.x: wrapper.width/2; origin.y: wrapper.height/2
+ axis.y: 1; axis.z: 0; angle: wrapper.PathView.angle
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/pathview3.qml b/tests/auto/declarative/qsgpathview/data/pathview3.qml
new file mode 100644
index 0000000000..ded5a3911c
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/pathview3.qml
@@ -0,0 +1,59 @@
+import QtQuick 2.0
+
+PathView {
+ id: photoPathView
+ y: 100; width: 800; height: 330; pathItemCount: 4; offset: 1
+ dragMargin: 24
+ preferredHighlightBegin: 0.50
+ preferredHighlightEnd: 0.50
+
+ path: Path {
+ startX: -50; startY: 40;
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: -45 }
+
+ PathCubic {
+ x: 400; y: 220
+ control1X: 140; control1Y: 40
+ control2X: 210; control2Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 1.2 }
+ PathAttribute { name: "angle"; value: 0 }
+
+ PathCubic {
+ x: 850; y: 40
+ control2X: 660; control2Y: 40
+ control1X: 590; control1Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: 45 }
+ }
+
+ model: ListModel {
+ id: rssModel
+ ListElement { lColor: "red" }
+ ListElement { lColor: "green" }
+ ListElement { lColor: "yellow" }
+ ListElement { lColor: "blue" }
+ ListElement { lColor: "purple" }
+ ListElement { lColor: "gray" }
+ ListElement { lColor: "brown" }
+ ListElement { lColor: "thistle" }
+ }
+
+ delegate: Component {
+ id: photoDelegate
+ Rectangle {
+ id: wrapper
+ width: 85; height: 85; color: lColor
+
+ transform: Rotation {
+ id: itemRotation; origin.x: wrapper.width/2; origin.y: wrapper.height/2
+ axis.y: 1; axis.z: 0
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/pathview_package.qml b/tests/auto/declarative/qsgpathview/data/pathview_package.qml
new file mode 100644
index 0000000000..2af57e6bb1
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/pathview_package.qml
@@ -0,0 +1,88 @@
+import QtQuick 2.0
+
+Item {
+ width: 800; height: 600
+ Component {
+ id: photoDelegate
+ Package {
+ Item { id: pathItem; objectName: "pathItem"; Package.name: 'path'; width: 85; height: 85; scale: pathItem.PathView.scale }
+ Item { id: linearItem; Package.name: 'linear'; width: 85; height: 85 }
+ Rectangle {
+ id: wrapper
+ width: 85; height: 85; color: lColor
+
+ transform: Rotation {
+ id: itemRotation; origin.x: wrapper.width/2; origin.y: wrapper.height/2
+ axis.y: 1; axis.z: 0
+ }
+ state: 'path'
+ states: [
+ State {
+ name: 'path'
+ ParentChange { target: wrapper; parent: pathItem; x: 0; y: 0 }
+ PropertyChanges { target: wrapper; opacity: pathItem.PathView.onPath ? 1.0 : 0 }
+ }
+ ]
+ }
+ }
+ }
+ ListModel {
+ id: rssModel
+ ListElement { lColor: "red" }
+ ListElement { lColor: "green" }
+ ListElement { lColor: "yellow" }
+ ListElement { lColor: "blue" }
+ ListElement { lColor: "purple" }
+ ListElement { lColor: "gray" }
+ ListElement { lColor: "brown" }
+ ListElement { lColor: "thistle" }
+ }
+ VisualDataModel { id: visualModel; model: rssModel; delegate: photoDelegate }
+
+ PathView {
+ id: photoPathView
+ objectName: "photoPathView"
+ width: 800; height: 330; pathItemCount: 4; offset: 1
+ dragMargin: 24
+ preferredHighlightBegin: 0.50
+ preferredHighlightEnd: 0.50
+
+ path: Path {
+ startX: -50; startY: 40;
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: -45 }
+
+ PathCubic {
+ x: 400; y: 220
+ control1X: 140; control1Y: 40
+ control2X: 210; control2Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 1.2 }
+ PathAttribute { name: "angle"; value: 0 }
+
+ PathCubic {
+ x: 850; y: 40
+ control2X: 660; control2Y: 40
+ control1X: 590; control1Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: 45 }
+ }
+
+ model: visualModel.parts.path
+ }
+
+ PathView {
+ y: 400; width: 800; height: 330; pathItemCount: 8
+
+ path: Path {
+ startX: 0; startY: 40;
+ PathLine { x: 800; y: 40 }
+ }
+
+ model: visualModel.parts.linear
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/propertychanges.qml b/tests/auto/declarative/qsgpathview/data/propertychanges.qml
new file mode 100644
index 0000000000..09b309f86f
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/propertychanges.qml
@@ -0,0 +1,116 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 350; height: 220; color: "white"
+ Component {
+ id: myDelegate
+ Item {
+ id: wrapper
+ width: 180; height: 40;
+ opacity: PathView.opacity
+ Column {
+ x: 5; y: 5
+ Text { text: '<b>Name:</b> ' + name }
+ Text { text: '<b>Number:</b> ' + number }
+ }
+ }
+ }
+
+ PathView {
+ preferredHighlightBegin: 0.1
+ preferredHighlightEnd: 0.1
+ dragMargin: 5.0
+ id: pathView
+ objectName: "pathView"
+ anchors.fill: parent
+ model: listModel
+ delegate: myDelegate
+ focus: true
+ path: Path {
+ id: myPath
+ objectName: "path"
+ startX: 220; startY: 200
+ PathAttribute { name: "opacity"; value: 1.0; objectName: "pathAttribute"; }
+ PathQuad { x: 220; y: 25; controlX: 260; controlY: 75 }
+ PathAttribute { name: "opacity"; value: 0.3 }
+ PathQuad { x: 220; y: 200; controlX: -20; controlY: 75 }
+ }
+ Timer {
+ interval: 2000; running: true; repeat: true
+ onTriggered: {
+ if (pathView.path == alternatePath)
+ pathView.path = myPath;
+ else
+ pathView.path = alternatePath;
+ }
+ }
+ }
+
+ data:[
+ ListModel {
+ id: listModel
+ ListElement {
+ name: "Bill Smith"
+ number: "555 3264"
+ }
+ ListElement {
+ name: "John Brown"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Sam Wise"
+ number: "555 0473"
+ }
+ ListElement {
+ name: "Bill Smith"
+ number: "555 3264"
+ }
+ ListElement {
+ name: "John Brown"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Sam Wise"
+ number: "555 0473"
+ }
+ ListElement {
+ name: "Bill Smith"
+ number: "555 3264"
+ }
+ ListElement {
+ name: "John Brown"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Sam Wise"
+ number: "555 0473"
+ }
+ },
+ ListModel {
+ objectName: "alternateModel"
+ ListElement {
+ name: "Jack"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Mary"
+ number: "555 3264"
+ }
+ },
+ Path {
+ id: alternatePath
+ objectName: "alternatePath"
+ startX: 100; startY: 40
+ PathAttribute { name: "opacity"; value: 0.0 }
+ PathLine { x: 100; y: 160 }
+ PathAttribute { name: "opacity"; value: 0.2 }
+ PathLine { x: 300; y: 160 }
+ PathAttribute { name: "opacity"; value: 0.0 }
+ PathLine { x: 300; y: 40 }
+ PathAttribute { name: "opacity"; value: 0.2 }
+ PathLine { x: 100; y: 40 }
+ }
+ ]
+}
+
+
diff --git a/tests/auto/declarative/qsgpathview/data/treemodel.qml b/tests/auto/declarative/qsgpathview/data/treemodel.qml
new file mode 100644
index 0000000000..fcf6922d00
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/treemodel.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+PathView {
+ width: 320
+ height: 240
+ function setRoot(index) {
+ vdm.rootIndex = vdm.modelIndex(index);
+ }
+ model: VisualDataModel {
+ id: vdm
+ model: myModel
+ delegate: Text { objectName: "wrapper"; text: display }
+ }
+
+ path: Path {
+ startX: 0; startY: 120
+ PathLine { x: 320; y: 120 }
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/undefinedpath.qml b/tests/auto/declarative/qsgpathview/data/undefinedpath.qml
new file mode 100644
index 0000000000..674e7cca8d
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/undefinedpath.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+
+PathView {
+ id: pathView
+ width: 240; height: 200
+ path: Path {
+ startX: pathView.undef/2.0; startY: 0
+ PathLine { x: pathView.undef/2.0; y: 0 }
+ }
+
+ delegate: Text { text: value }
+ model: ListModel {
+ ListElement { value: "one" }
+ ListElement { value: "two" }
+ ListElement { value: "three" }
+ }
+}
diff --git a/tests/auto/declarative/qsgpathview/data/vdm.qml b/tests/auto/declarative/qsgpathview/data/vdm.qml
new file mode 100644
index 0000000000..839393d9bd
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/data/vdm.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+PathView {
+ id: pathView
+ width: 240; height: 320
+
+ pathItemCount: 4
+ preferredHighlightBegin : 0.5
+ preferredHighlightEnd : 0.5
+
+ path: Path {
+ startX: 120; startY: 20;
+ PathLine { x: 120; y: 300 }
+ }
+
+ ListModel {
+ id: mo
+ ListElement { value: "one" }
+ ListElement { value: "two" }
+ ListElement { value: "three" }
+ }
+
+ model: VisualDataModel {
+ delegate: Text { text: model.value }
+ model : mo
+ }
+}
+
diff --git a/tests/auto/declarative/qsgpathview/qsgpathview.pro b/tests/auto/declarative/qsgpathview/qsgpathview.pro
new file mode 100644
index 0000000000..4380b557fb
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/qsgpathview.pro
@@ -0,0 +1,16 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qsgpathview.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgpathview/tst_qsgpathview.cpp b/tests/auto/declarative/qsgpathview/tst_qsgpathview.cpp
new file mode 100644
index 0000000000..df8057c4c4
--- /dev/null
+++ b/tests/auto/declarative/qsgpathview/tst_qsgpathview.cpp
@@ -0,0 +1,1058 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtDeclarative/qsgview.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/private/qsgpathview_p.h>
+#include <QtDeclarative/private/qdeclarativepath_p.h>
+#include <QtDeclarative/private/qsgtext_p.h>
+#include <QtDeclarative/private/qsgrectangle_p.h>
+#include <QtDeclarative/private/qdeclarativelistmodel_p.h>
+#include <QtDeclarative/private/qdeclarativevaluetype_p.h>
+#include <QAbstractListModel>
+#include <QStringListModel>
+#include <QStandardItemModel>
+#include <QFile>
+
+#include "../../../shared/util.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+static void initStandardTreeModel(QStandardItemModel *model)
+{
+ QStandardItem *item;
+ item = new QStandardItem(QLatin1String("Row 1 Item"));
+ model->insertRow(0, item);
+
+ item = new QStandardItem(QLatin1String("Row 2 Item"));
+ item->setCheckable(true);
+ model->insertRow(1, item);
+
+ QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
+ item->setChild(0, childItem);
+
+ item = new QStandardItem(QLatin1String("Row 3 Item"));
+ item->setIcon(QIcon());
+ model->insertRow(2, item);
+}
+
+
+class tst_QSGPathView : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QSGPathView();
+
+private slots:
+ void initValues();
+ void items();
+ void dataModel();
+ void pathview2();
+ void pathview3();
+ void path();
+ void pathMoved();
+ void setCurrentIndex();
+ void resetModel();
+ void propertyChanges();
+ void pathChanges();
+ void componentChanges();
+ void modelChanges();
+ void pathUpdateOnStartChanged();
+ void package();
+ void emptyModel();
+ void closed();
+ void pathUpdate();
+ void visualDataModel();
+ void undefinedPath();
+ void mouseDrag();
+ void treeModel();
+ void changePreferredHighlight();
+
+private:
+ QSGView *createView();
+ template<typename T>
+ T *findItem(QSGItem *parent, const QString &objectName, int index=-1);
+ template<typename T>
+ QList<T*> findItems(QSGItem *parent, const QString &objectName);
+};
+
+class TestObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool error READ error WRITE setError)
+ Q_PROPERTY(bool useModel READ useModel NOTIFY useModelChanged)
+ Q_PROPERTY(int pathItemCount READ pathItemCount NOTIFY pathItemCountChanged)
+
+public:
+ TestObject() : QObject(), mError(true), mUseModel(true), mPathItemCount(-1) {}
+
+ bool error() const { return mError; }
+ void setError(bool err) { mError = err; }
+
+ bool useModel() const { return mUseModel; }
+ void setUseModel(bool use) { mUseModel = use; emit useModelChanged(); }
+
+ int pathItemCount() const { return mPathItemCount; }
+ void setPathItemCount(int count) { mPathItemCount = count; emit pathItemCountChanged(); }
+
+signals:
+ void useModelChanged();
+ void pathItemCountChanged();
+
+private:
+ bool mError;
+ bool mUseModel;
+ int mPathItemCount;
+};
+
+class TestModel : public QAbstractListModel
+{
+public:
+ enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
+
+ TestModel(QObject *parent=0) : QAbstractListModel(parent) {
+ QHash<int, QByteArray> roles;
+ roles[Name] = "name";
+ roles[Number] = "number";
+ setRoleNames(roles);
+ }
+
+ int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
+ QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
+ QVariant rv;
+ if (role == Name)
+ rv = list.at(index.row()).first;
+ else if (role == Number)
+ rv = list.at(index.row()).second;
+
+ return rv;
+ }
+
+ int count() const { return rowCount(); }
+ QString name(int index) const { return list.at(index).first; }
+ QString number(int index) const { return list.at(index).second; }
+
+ void addItem(const QString &name, const QString &number) {
+ beginInsertRows(QModelIndex(), list.count(), list.count());
+ list.append(QPair<QString,QString>(name, number));
+ endInsertRows();
+ }
+
+ void insertItem(int index, const QString &name, const QString &number) {
+ beginInsertRows(QModelIndex(), index, index);
+ list.insert(index, QPair<QString,QString>(name, number));
+ endInsertRows();
+ }
+
+ void removeItem(int index) {
+ beginRemoveRows(QModelIndex(), index, index);
+ list.removeAt(index);
+ endRemoveRows();
+ }
+
+ void moveItem(int from, int to) {
+ beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
+ list.move(from, to);
+ endMoveRows();
+ }
+
+ void modifyItem(int idx, const QString &name, const QString &number) {
+ list[idx] = QPair<QString,QString>(name, number);
+ emit dataChanged(index(idx,0), index(idx,0));
+ }
+
+private:
+ QList<QPair<QString,QString> > list;
+};
+
+
+tst_QSGPathView::tst_QSGPathView()
+{
+}
+
+void tst_QSGPathView::initValues()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathview1.qml"));
+ QSGPathView *obj = qobject_cast<QSGPathView*>(c.create());
+
+ QVERIFY(obj != 0);
+ QVERIFY(obj->path() == 0);
+ QVERIFY(obj->delegate() == 0);
+ QCOMPARE(obj->model(), QVariant());
+ QCOMPARE(obj->currentIndex(), 0);
+ QCOMPARE(obj->offset(), 0.);
+ QCOMPARE(obj->preferredHighlightBegin(), 0.);
+ QCOMPARE(obj->dragMargin(), 0.);
+ QCOMPARE(obj->count(), 0);
+ QCOMPARE(obj->pathItemCount(), -1);
+}
+
+void tst_QSGPathView::items()
+{
+ QSGView *canvas = createView();
+
+ TestModel model;
+ model.addItem("Fred", "12345");
+ model.addItem("John", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Bill", "4321");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview0.qml"));
+ qApp->processEvents();
+
+ QSGPathView *pathview = findItem<QSGPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ QCOMPARE(pathview->childItems().count(), model.count()+1); // assumes all are visible, including highlight
+
+ for (int i = 0; i < model.count(); ++i) {
+ QSGText *name = findItem<QSGText>(pathview, "textName", i);
+ QVERIFY(name != 0);
+ QCOMPARE(name->text(), model.name(i));
+ QSGText *number = findItem<QSGText>(pathview, "textNumber", i);
+ QVERIFY(number != 0);
+ QCOMPARE(number->text(), model.number(i));
+ }
+
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+
+ QVERIFY(pathview->highlightItem());
+ QPointF start = path->pointAt(0.0);
+ QPointF offset;
+ offset.setX(pathview->highlightItem()->width()/2);
+ offset.setY(pathview->highlightItem()->height()/2);
+ QCOMPARE(pathview->highlightItem()->pos() + offset, start);
+
+ delete canvas;
+}
+
+void tst_QSGPathView::pathview2()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathview2.qml"));
+ QSGPathView *obj = qobject_cast<QSGPathView*>(c.create());
+
+ QVERIFY(obj != 0);
+ QVERIFY(obj->path() != 0);
+ QVERIFY(obj->delegate() != 0);
+ QVERIFY(obj->model() != QVariant());
+ QCOMPARE(obj->currentIndex(), 0);
+ QCOMPARE(obj->offset(), 0.);
+ QCOMPARE(obj->preferredHighlightBegin(), 0.);
+ QCOMPARE(obj->dragMargin(), 0.);
+ QCOMPARE(obj->count(), 8);
+ QCOMPARE(obj->pathItemCount(), 10);
+}
+
+void tst_QSGPathView::pathview3()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathview3.qml"));
+ QSGPathView *obj = qobject_cast<QSGPathView*>(c.create());
+
+ QVERIFY(obj != 0);
+ QVERIFY(obj->path() != 0);
+ QVERIFY(obj->delegate() != 0);
+ QVERIFY(obj->model() != QVariant());
+ QCOMPARE(obj->currentIndex(), 0);
+ QCOMPARE(obj->offset(), 1.0);
+ QCOMPARE(obj->preferredHighlightBegin(), 0.5);
+ QCOMPARE(obj->dragMargin(), 24.);
+ QCOMPARE(obj->count(), 8);
+ QCOMPARE(obj->pathItemCount(), 4);
+}
+
+void tst_QSGPathView::path()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathtest.qml"));
+ QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
+
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->startX(), 120.);
+ QCOMPARE(obj->startY(), 100.);
+ QVERIFY(obj->path() != QPainterPath());
+
+ QDeclarativeListReference list(obj, "pathElements");
+ QCOMPARE(list.count(), 5);
+
+ QDeclarativePathAttribute* attr = qobject_cast<QDeclarativePathAttribute*>(list.at(0));
+ QVERIFY(attr != 0);
+ QCOMPARE(attr->name(), QString("scale"));
+ QCOMPARE(attr->value(), 1.0);
+
+ QDeclarativePathQuad* quad = qobject_cast<QDeclarativePathQuad*>(list.at(1));
+ QVERIFY(quad != 0);
+ QCOMPARE(quad->x(), 120.);
+ QCOMPARE(quad->y(), 25.);
+ QCOMPARE(quad->controlX(), 260.);
+ QCOMPARE(quad->controlY(), 75.);
+
+ QDeclarativePathPercent* perc = qobject_cast<QDeclarativePathPercent*>(list.at(2));
+ QVERIFY(perc != 0);
+ QCOMPARE(perc->value(), 0.3);
+
+ QDeclarativePathLine* line = qobject_cast<QDeclarativePathLine*>(list.at(3));
+ QVERIFY(line != 0);
+ QCOMPARE(line->x(), 120.);
+ QCOMPARE(line->y(), 100.);
+
+ QDeclarativePathCubic* cubic = qobject_cast<QDeclarativePathCubic*>(list.at(4));
+ QVERIFY(cubic != 0);
+ QCOMPARE(cubic->x(), 180.);
+ QCOMPARE(cubic->y(), 0.);
+ QCOMPARE(cubic->control1X(), -10.);
+ QCOMPARE(cubic->control1Y(), 90.);
+ QCOMPARE(cubic->control2X(), 210.);
+ QCOMPARE(cubic->control2Y(), 90.);
+}
+
+void tst_QSGPathView::dataModel()
+{
+ QSGView *canvas = createView();
+ canvas->show();
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ TestModel model;
+ model.addItem("red", "1");
+ model.addItem("green", "2");
+ model.addItem("blue", "3");
+ model.addItem("purple", "4");
+ model.addItem("gray", "5");
+ model.addItem("brown", "6");
+ model.addItem("yellow", "7");
+ model.addItem("thistle", "8");
+ model.addItem("cyan", "9");
+ model.addItem("peachpuff", "10");
+ model.addItem("powderblue", "11");
+ model.addItem("gold", "12");
+ model.addItem("sandybrown", "13");
+
+ ctxt->setContextProperty("testData", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/datamodel.qml"));
+ qApp->processEvents();
+
+ QSGPathView *pathview = qobject_cast<QSGPathView*>(canvas->rootObject());
+ QVERIFY(pathview != 0);
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
+ QVERIFY(testObject->error() == false);
+
+ QSGItem *item = findItem<QSGItem>(pathview, "wrapper", 0);
+ QVERIFY(item);
+ QCOMPARE(item->x(), 110.0);
+ QCOMPARE(item->y(), 10.0);
+
+ model.insertItem(4, "orange", "10");
+ QTest::qWait(100);
+
+ QTRY_COMPARE(findItems<QSGItem>(pathview, "wrapper").count(), 14);
+
+ QVERIFY(pathview->currentIndex() == 0);
+
+ QSGText *text = findItem<QSGText>(pathview, "myText", 4);
+ QVERIFY(text);
+ QCOMPARE(text->text(), model.name(4));
+
+ model.removeItem(2);
+ text = findItem<QSGText>(pathview, "myText", 2);
+ QVERIFY(text);
+ QCOMPARE(text->text(), model.name(2));
+
+ testObject->setPathItemCount(5);
+ QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
+ QVERIFY(testObject->error() == false);
+
+ QTRY_COMPARE(findItems<QSGItem>(pathview, "wrapper").count(), 5);
+
+ QSGRectangle *testItem = findItem<QSGRectangle>(pathview, "wrapper", 4);
+ QVERIFY(testItem != 0);
+ testItem = findItem<QSGRectangle>(pathview, "wrapper", 5);
+ QVERIFY(testItem == 0);
+
+ pathview->setCurrentIndex(1);
+
+ model.insertItem(2, "pink", "2");
+ QTest::qWait(100);
+
+ QTRY_COMPARE(findItems<QSGItem>(pathview, "wrapper").count(), 5);
+ QVERIFY(pathview->currentIndex() == 1);
+
+ text = findItem<QSGText>(pathview, "myText", 2);
+ QVERIFY(text);
+ QCOMPARE(text->text(), model.name(2));
+
+ model.removeItem(3);
+ QTRY_COMPARE(findItems<QSGItem>(pathview, "wrapper").count(), 5);
+ text = findItem<QSGText>(pathview, "myText", 3);
+ QVERIFY(text);
+ QCOMPARE(text->text(), model.name(3));
+
+ model.moveItem(3, 5);
+ QTRY_COMPARE(findItems<QSGItem>(pathview, "wrapper").count(), 5);
+ QList<QSGItem*> items = findItems<QSGItem>(pathview, "wrapper");
+ foreach (QSGItem *item, items) {
+ QVERIFY(item->property("onPath").toBool());
+ }
+
+ // QTBUG-14199
+ pathview->setOffset(7);
+ pathview->setOffset(0);
+ QCOMPARE(findItems<QSGItem>(pathview, "wrapper").count(), 5);
+
+ pathview->setCurrentIndex(model.count()-1);
+ model.removeItem(model.count()-1);
+ QCOMPARE(pathview->currentIndex(), model.count()-1);
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QSGPathView::pathMoved()
+{
+ QSGView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ model.addItem("Ben", "12345");
+ model.addItem("Bohn", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Bill", "4321");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview0.qml"));
+ qApp->processEvents();
+
+ QSGPathView *pathview = findItem<QSGPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ QSGRectangle *firstItem = findItem<QSGRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+ QPointF start = path->pointAt(0.0);
+ QPointF offset;//Center of item is at point, but pos is from corner
+ offset.setX(firstItem->width()/2);
+ offset.setY(firstItem->height()/2);
+ QCOMPARE(firstItem->pos() + offset, start);
+ pathview->setOffset(1.0);
+
+ for(int i=0; i<model.count(); i++){
+ QSGRectangle *curItem = findItem<QSGRectangle>(pathview, "wrapper", i);
+ QPointF itemPos(path->pointAt(0.25 + i*0.25));
+ QCOMPARE(curItem->pos() + offset, QPointF(qRound(itemPos.x()), qRound(itemPos.y())));
+ }
+
+ pathview->setOffset(0.0);
+ QCOMPARE(firstItem->pos() + offset, start);
+
+ // Change delegate size
+ pathview->setOffset(0.1);
+ pathview->setOffset(0.0);
+ canvas->rootObject()->setProperty("delegateWidth", 30);
+ QCOMPARE(firstItem->width(), 30.0);
+ offset.setX(firstItem->width()/2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+
+ // Change delegate scale
+ pathview->setOffset(0.1);
+ pathview->setOffset(0.0);
+ canvas->rootObject()->setProperty("delegateScale", 1.2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+
+ delete canvas;
+}
+
+void tst_QSGPathView::setCurrentIndex()
+{
+ QSGView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ model.addItem("Ben", "12345");
+ model.addItem("Bohn", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Bill", "4321");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview0.qml"));
+ qApp->processEvents();
+
+ QSGPathView *pathview = findItem<QSGPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ QSGRectangle *firstItem = findItem<QSGRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+ QPointF start = path->pointAt(0.0);
+ QPointF offset;//Center of item is at point, but pos is from corner
+ offset.setX(firstItem->width()/2);
+ offset.setY(firstItem->height()/2);
+ QCOMPARE(firstItem->pos() + offset, start);
+ QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 0);
+
+ pathview->setCurrentIndex(2);
+
+ firstItem = findItem<QSGRectangle>(pathview, "wrapper", 2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 2);
+ QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 2);
+
+ pathview->decrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 1);
+ firstItem = findItem<QSGRectangle>(pathview, "wrapper", 1);
+ QVERIFY(firstItem);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+
+ pathview->decrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 0);
+ firstItem = findItem<QSGRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+
+ pathview->decrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 3);
+ firstItem = findItem<QSGRectangle>(pathview, "wrapper", 3);
+ QVERIFY(firstItem);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+
+ pathview->incrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 0);
+ firstItem = findItem<QSGRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+
+ delete canvas;
+}
+
+void tst_QSGPathView::resetModel()
+{
+ QSGView *canvas = createView();
+
+ QStringList strings;
+ strings << "one" << "two" << "three";
+ QStringListModel model(strings);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaypath.qml"));
+ qApp->processEvents();
+
+ QSGPathView *pathview = findItem<QSGPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ QCOMPARE(pathview->count(), model.rowCount());
+
+ for (int i = 0; i < model.rowCount(); ++i) {
+ QSGText *display = findItem<QSGText>(pathview, "displayText", i);
+ QVERIFY(display != 0);
+ QCOMPARE(display->text(), strings.at(i));
+ }
+
+ strings.clear();
+ strings << "four" << "five" << "six" << "seven";
+ model.setStringList(strings);
+
+ QCOMPARE(pathview->count(), model.rowCount());
+
+ for (int i = 0; i < model.rowCount(); ++i) {
+ QSGText *display = findItem<QSGText>(pathview, "displayText", i);
+ QVERIFY(display != 0);
+ QCOMPARE(display->text(), strings.at(i));
+ }
+
+ delete canvas;
+}
+
+void tst_QSGPathView::propertyChanges()
+{
+ QSGView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
+
+ QSGPathView *pathView = canvas->rootObject()->findChild<QSGPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QSignalSpy snapPositionSpy(pathView, SIGNAL(preferredHighlightBeginChanged()));
+ QSignalSpy dragMarginSpy(pathView, SIGNAL(dragMarginChanged()));
+
+ QCOMPARE(pathView->preferredHighlightBegin(), 0.1);
+ QCOMPARE(pathView->dragMargin(), 5.0);
+
+ pathView->setPreferredHighlightBegin(0.4);
+ pathView->setPreferredHighlightEnd(0.4);
+ pathView->setDragMargin(20.0);
+
+ QCOMPARE(pathView->preferredHighlightBegin(), 0.4);
+ QCOMPARE(pathView->preferredHighlightEnd(), 0.4);
+ QCOMPARE(pathView->dragMargin(), 20.0);
+
+ QCOMPARE(snapPositionSpy.count(), 1);
+ QCOMPARE(dragMarginSpy.count(), 1);
+
+ pathView->setPreferredHighlightBegin(0.4);
+ pathView->setPreferredHighlightEnd(0.4);
+ pathView->setDragMargin(20.0);
+
+ QCOMPARE(snapPositionSpy.count(), 1);
+ QCOMPARE(dragMarginSpy.count(), 1);
+ delete canvas;
+}
+
+void tst_QSGPathView::pathChanges()
+{
+ QSGView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
+
+ QSGPathView *pathView = canvas->rootObject()->findChild<QSGPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QDeclarativePath *path = canvas->rootObject()->findChild<QDeclarativePath*>("path");
+ QVERIFY(path);
+
+ QSignalSpy startXSpy(path, SIGNAL(startXChanged()));
+ QSignalSpy startYSpy(path, SIGNAL(startYChanged()));
+
+ QCOMPARE(path->startX(), 220.0);
+ QCOMPARE(path->startY(), 200.0);
+
+ path->setStartX(240.0);
+ path->setStartY(220.0);
+
+ QCOMPARE(path->startX(), 240.0);
+ QCOMPARE(path->startY(), 220.0);
+
+ QCOMPARE(startXSpy.count(),1);
+ QCOMPARE(startYSpy.count(),1);
+
+ path->setStartX(240);
+ path->setStartY(220);
+
+ QCOMPARE(startXSpy.count(),1);
+ QCOMPARE(startYSpy.count(),1);
+
+ QDeclarativePath *alternatePath = canvas->rootObject()->findChild<QDeclarativePath*>("alternatePath");
+ QVERIFY(alternatePath);
+
+ QSignalSpy pathSpy(pathView, SIGNAL(pathChanged()));
+
+ QCOMPARE(pathView->path(), path);
+
+ pathView->setPath(alternatePath);
+ QCOMPARE(pathView->path(), alternatePath);
+ QCOMPARE(pathSpy.count(),1);
+
+ pathView->setPath(alternatePath);
+ QCOMPARE(pathSpy.count(),1);
+
+ QDeclarativePathAttribute *pathAttribute = canvas->rootObject()->findChild<QDeclarativePathAttribute*>("pathAttribute");
+ QVERIFY(pathAttribute);
+
+ QSignalSpy nameSpy(pathAttribute, SIGNAL(nameChanged()));
+ QCOMPARE(pathAttribute->name(), QString("opacity"));
+
+ pathAttribute->setName("scale");
+ QCOMPARE(pathAttribute->name(), QString("scale"));
+ QCOMPARE(nameSpy.count(),1);
+
+ pathAttribute->setName("scale");
+ QCOMPARE(nameSpy.count(),1);
+ delete canvas;
+}
+
+void tst_QSGPathView::componentChanges()
+{
+ QSGView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
+
+ QSGPathView *pathView = canvas->rootObject()->findChild<QSGPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QDeclarativeComponent delegateComponent(canvas->engine());
+ delegateComponent.setData("import QtQuick 2.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
+
+ QSignalSpy delegateSpy(pathView, SIGNAL(delegateChanged()));
+
+ pathView->setDelegate(&delegateComponent);
+ QCOMPARE(pathView->delegate(), &delegateComponent);
+ QCOMPARE(delegateSpy.count(),1);
+
+ pathView->setDelegate(&delegateComponent);
+ QCOMPARE(delegateSpy.count(),1);
+ delete canvas;
+}
+
+void tst_QSGPathView::modelChanges()
+{
+ QSGView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
+
+ QSGPathView *pathView = canvas->rootObject()->findChild<QSGPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
+ QVERIFY(alternateModel);
+ QVariant modelVariant = QVariant::fromValue(alternateModel);
+ QSignalSpy modelSpy(pathView, SIGNAL(modelChanged()));
+
+ pathView->setModel(modelVariant);
+ QCOMPARE(pathView->model(), modelVariant);
+ QCOMPARE(modelSpy.count(),1);
+
+ pathView->setModel(modelVariant);
+ QCOMPARE(modelSpy.count(),1);
+
+ pathView->setModel(QVariant());
+ QCOMPARE(modelSpy.count(),2);
+
+ delete canvas;
+}
+
+void tst_QSGPathView::pathUpdateOnStartChanged()
+{
+ QSGView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathUpdateOnStartChanged.qml"));
+
+ QSGPathView *pathView = canvas->rootObject()->findChild<QSGPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QDeclarativePath *path = canvas->rootObject()->findChild<QDeclarativePath*>("path");
+ QVERIFY(path);
+ QCOMPARE(path->startX(), 400.0);
+ QCOMPARE(path->startY(), 300.0);
+
+ QSGItem *item = findItem<QSGItem>(pathView, "wrapper", 0);
+ QVERIFY(item);
+ QCOMPARE(item->x(), path->startX() - item->width() / 2.0);
+ QCOMPARE(item->y(), path->startY() - item->height() / 2.0);
+
+ delete canvas;
+}
+
+void tst_QSGPathView::package()
+{
+ QSGView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview_package.qml"));
+
+ QSGPathView *pathView = canvas->rootObject()->findChild<QSGPathView*>("photoPathView");
+ QVERIFY(pathView);
+
+ QSGItem *item = findItem<QSGItem>(pathView, "pathItem");
+ QVERIFY(item);
+ QVERIFY(item->scale() != 1.0);
+
+ delete canvas;
+}
+
+//QTBUG-13017
+void tst_QSGPathView::emptyModel()
+{
+ QSGView *canvas = createView();
+
+ QStringListModel model;
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("emptyModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/emptymodel.qml"));
+ qApp->processEvents();
+
+ QSGPathView *pathview = qobject_cast<QSGPathView*>(canvas->rootObject());
+ QVERIFY(pathview != 0);
+
+ QCOMPARE(pathview->offset(), qreal(0.0));
+
+ delete canvas;
+}
+
+void tst_QSGPathView::closed()
+{
+ QDeclarativeEngine engine;
+
+ {
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/openPath.qml"));
+ QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
+ QVERIFY(obj);
+ QCOMPARE(obj->isClosed(), false);
+ delete obj;
+ }
+
+ {
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/closedPath.qml"));
+ QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
+ QVERIFY(obj);
+ QCOMPARE(obj->isClosed(), true);
+ delete obj;
+ }
+}
+
+// QTBUG-14239
+void tst_QSGPathView::pathUpdate()
+{
+ QSGView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathUpdate.qml"));
+
+ QSGPathView *pathView = canvas->rootObject()->findChild<QSGPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QSGItem *item = findItem<QSGItem>(pathView, "wrapper", 0);
+ QVERIFY(item);
+ QCOMPARE(item->x(), 150.0);
+
+ delete canvas;
+}
+
+void tst_QSGPathView::visualDataModel()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/vdm.qml"));
+
+ QSGPathView *obj = qobject_cast<QSGPathView*>(c.create());
+ QVERIFY(obj != 0);
+
+ QCOMPARE(obj->count(), 3);
+
+ delete obj;
+}
+
+void tst_QSGPathView::undefinedPath()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/undefinedpath.qml"));
+
+ QSGPathView *obj = qobject_cast<QSGPathView*>(c.create());
+ QVERIFY(obj != 0);
+
+ QCOMPARE(obj->count(), 3);
+
+ delete obj;
+}
+
+void tst_QSGPathView::mouseDrag()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/dragpath.qml"));
+ canvas->show();
+ QApplication::setActiveWindow(canvas);
+ QTest::qWaitForWindowShown(canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
+
+ QSGPathView *pathview = qobject_cast<QSGPathView*>(canvas->rootObject());
+ QVERIFY(pathview != 0);
+
+ int current = pathview->currentIndex();
+
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(10,100));
+
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(30,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(canvas, &mv);
+ }
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(90,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(canvas, &mv);
+ }
+
+ QVERIFY(pathview->currentIndex() != current);
+
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(40,100));
+
+ delete canvas;
+}
+
+void tst_QSGPathView::treeModel()
+{
+ QSGView *canvas = createView();
+ canvas->show();
+
+ QStandardItemModel model;
+ initStandardTreeModel(&model);
+ canvas->engine()->rootContext()->setContextProperty("myModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/treemodel.qml"));
+
+ QSGPathView *pathview = qobject_cast<QSGPathView*>(canvas->rootObject());
+ QVERIFY(pathview != 0);
+ QCOMPARE(pathview->count(), 3);
+
+ QSGText *item = findItem<QSGText>(pathview, "wrapper", 0);
+ QVERIFY(item);
+ QCOMPARE(item->text(), QLatin1String("Row 1 Item"));
+
+ QVERIFY(QMetaObject::invokeMethod(pathview, "setRoot", Q_ARG(QVariant, 1)));
+ QCOMPARE(pathview->count(), 1);
+
+ QTRY_VERIFY(item = findItem<QSGText>(pathview, "wrapper", 0));
+ QTRY_COMPARE(item->text(), QLatin1String("Row 2 Child Item"));
+
+ delete canvas;
+}
+
+void tst_QSGPathView::changePreferredHighlight()
+{
+ QSGView *canvas = createView();
+ canvas->setFixedSize(400,200);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/dragpath.qml"));
+ canvas->show();
+ QApplication::setActiveWindow(canvas);
+ QTest::qWaitForWindowShown(canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
+
+ QSGPathView *pathview = qobject_cast<QSGPathView*>(canvas->rootObject());
+ QVERIFY(pathview != 0);
+
+ int current = pathview->currentIndex();
+ QCOMPARE(current, 0);
+
+ QSGRectangle *firstItem = findItem<QSGRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+ QPointF start = path->pointAt(0.5);
+ start.setX(qRound(start.x()));
+ start.setY(qRound(start.y()));
+ QPointF offset;//Center of item is at point, but pos is from corner
+ offset.setX(firstItem->width()/2);
+ offset.setY(firstItem->height()/2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+
+ pathview->setPreferredHighlightBegin(0.8);
+ pathview->setPreferredHighlightEnd(0.8);
+ start = path->pointAt(0.8);
+ start.setX(qRound(start.x()));
+ start.setY(qRound(start.y()));
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ QCOMPARE(pathview->currentIndex(), 0);
+
+ delete canvas;
+}
+
+QSGView *tst_QSGPathView::createView()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ return canvas;
+}
+
+/*
+ Find an item with the specified objectName. If index is supplied then the
+ item must also evaluate the {index} expression equal to index
+ */
+template<typename T>
+T *tst_QSGPathView::findItem(QSGItem *parent, const QString &objectName, int index)
+{
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->childItems().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ if (index != -1) {
+ QDeclarativeExpression e(qmlContext(item), item, "index");
+ if (e.evaluate().toInt() == index)
+ return static_cast<T*>(item);
+ } else {
+ return static_cast<T*>(item);
+ }
+ }
+ item = findItem<T>(item, objectName, index);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+}
+
+template<typename T>
+QList<T*> tst_QSGPathView::findItems(QSGItem *parent, const QString &objectName)
+{
+ QList<T*> items;
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->QSGItem::children().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
+ items.append(static_cast<T*>(item));
+ items += findItems<T>(item, objectName);
+ }
+
+ return items;
+}
+
+QTEST_MAIN(tst_QSGPathView)
+
+#include "tst_qsgpathview.moc"
diff --git a/tests/auto/declarative/qsgpincharea/data/pinchproperties.qml b/tests/auto/declarative/qsgpincharea/data/pinchproperties.qml
new file mode 100644
index 0000000000..a1cd11302f
--- /dev/null
+++ b/tests/auto/declarative/qsgpincharea/data/pinchproperties.qml
@@ -0,0 +1,46 @@
+import QtQuick 2.0
+Rectangle {
+ id: whiteRect
+ property variant center
+ property real scale
+ width: 240; height: 320
+ color: "white"
+ Rectangle {
+ id: blackRect
+ objectName: "blackrect"
+ color: "black"
+ y: 50
+ x: 50
+ width: 100
+ height: 100
+ opacity: (whiteRect.width-blackRect.x+whiteRect.height-blackRect.y-199)/200
+ Text { text: blackRect.opacity}
+ PinchArea {
+ id: pincharea
+ objectName: "pincharea"
+ anchors.fill: parent
+ pinch.target: blackRect
+ pinch.dragAxis: Drag.XandYAxis
+ pinch.minimumX: 0
+ pinch.maximumX: whiteRect.width-blackRect.width
+ pinch.minimumY: 0
+ pinch.maximumY: whiteRect.height-blackRect.height
+ pinch.minimumScale: 1.0
+ pinch.maximumScale: 2.0
+ pinch.minimumRotation: 0.0
+ pinch.maximumRotation: 90.0
+ onPinchStarted: {
+ whiteRect.center = pinch.center
+ whiteRect.scale = pinch.scale
+ }
+ onPinchUpdated: {
+ whiteRect.center = pinch.center
+ whiteRect.scale = pinch.scale
+ }
+ onPinchFinished: {
+ whiteRect.center = pinch.center
+ whiteRect.scale = pinch.scale
+ }
+ }
+ }
+ }
diff --git a/tests/auto/declarative/qsgpincharea/qsgpincharea.pro b/tests/auto/declarative/qsgpincharea/qsgpincharea.pro
new file mode 100644
index 0000000000..6f785abf63
--- /dev/null
+++ b/tests/auto/declarative/qsgpincharea/qsgpincharea.pro
@@ -0,0 +1,16 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qsgpincharea.cpp
+
+symbian: {
+ importFiles.sources = data
+ importFiles.path = .
+ DEPLOYMENT = importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgpincharea/tst_qsgpincharea.cpp b/tests/auto/declarative/qsgpincharea/tst_qsgpincharea.cpp
new file mode 100644
index 0000000000..01895a69bd
--- /dev/null
+++ b/tests/auto/declarative/qsgpincharea/tst_qsgpincharea.cpp
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtTest/QSignalSpy>
+#include <private/qsgpincharea_p.h>
+#include <private/qsgrectangle_p.h>
+#include <QtDeclarative/qsgview.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_QSGPinchArea: public QObject
+{
+ Q_OBJECT
+private slots:
+ void pinchProperties();
+ void scale();
+ void pan();
+
+private:
+ QSGView *createView();
+};
+
+void tst_QSGPinchArea::pinchProperties()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pinchproperties.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGPinchArea *pinchArea = canvas->rootObject()->findChild<QSGPinchArea*>("pincharea");
+ QSGPinch *pinch = pinchArea->pinch();
+ QVERIFY(pinchArea != 0);
+ QVERIFY(pinch != 0);
+
+ // target
+ QSGItem *blackRect = canvas->rootObject()->findChild<QSGItem*>("blackrect");
+ QVERIFY(blackRect != 0);
+ QVERIFY(blackRect == pinch->target());
+ QSGItem *rootItem = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(rootItem != 0);
+ QSignalSpy targetSpy(pinch, SIGNAL(targetChanged()));
+ pinch->setTarget(rootItem);
+ QCOMPARE(targetSpy.count(),1);
+ pinch->setTarget(rootItem);
+ QCOMPARE(targetSpy.count(),1);
+
+ // axis
+ QCOMPARE(pinch->axis(), QSGPinch::XandYAxis);
+ QSignalSpy axisSpy(pinch, SIGNAL(dragAxisChanged()));
+ pinch->setAxis(QSGPinch::XAxis);
+ QCOMPARE(pinch->axis(), QSGPinch::XAxis);
+ QCOMPARE(axisSpy.count(),1);
+ pinch->setAxis(QSGPinch::XAxis);
+ QCOMPARE(axisSpy.count(),1);
+
+ // minimum and maximum drag properties
+ QSignalSpy xminSpy(pinch, SIGNAL(minimumXChanged()));
+ QSignalSpy xmaxSpy(pinch, SIGNAL(maximumXChanged()));
+ QSignalSpy yminSpy(pinch, SIGNAL(minimumYChanged()));
+ QSignalSpy ymaxSpy(pinch, SIGNAL(maximumYChanged()));
+
+ QCOMPARE(pinch->xmin(), 0.0);
+ QCOMPARE(pinch->xmax(), rootItem->width()-blackRect->width());
+ QCOMPARE(pinch->ymin(), 0.0);
+ QCOMPARE(pinch->ymax(), rootItem->height()-blackRect->height());
+
+ pinch->setXmin(10);
+ pinch->setXmax(10);
+ pinch->setYmin(10);
+ pinch->setYmax(10);
+
+ QCOMPARE(pinch->xmin(), 10.0);
+ QCOMPARE(pinch->xmax(), 10.0);
+ QCOMPARE(pinch->ymin(), 10.0);
+ QCOMPARE(pinch->ymax(), 10.0);
+
+ QCOMPARE(xminSpy.count(),1);
+ QCOMPARE(xmaxSpy.count(),1);
+ QCOMPARE(yminSpy.count(),1);
+ QCOMPARE(ymaxSpy.count(),1);
+
+ pinch->setXmin(10);
+ pinch->setXmax(10);
+ pinch->setYmin(10);
+ pinch->setYmax(10);
+
+ QCOMPARE(xminSpy.count(),1);
+ QCOMPARE(xmaxSpy.count(),1);
+ QCOMPARE(yminSpy.count(),1);
+ QCOMPARE(ymaxSpy.count(),1);
+
+ // minimum and maximum scale properties
+ QSignalSpy scaleMinSpy(pinch, SIGNAL(minimumScaleChanged()));
+ QSignalSpy scaleMaxSpy(pinch, SIGNAL(maximumScaleChanged()));
+
+ QCOMPARE(pinch->minimumScale(), 1.0);
+ QCOMPARE(pinch->maximumScale(), 2.0);
+
+ pinch->setMinimumScale(0.5);
+ pinch->setMaximumScale(1.5);
+
+ QCOMPARE(pinch->minimumScale(), 0.5);
+ QCOMPARE(pinch->maximumScale(), 1.5);
+
+ QCOMPARE(scaleMinSpy.count(),1);
+ QCOMPARE(scaleMaxSpy.count(),1);
+
+ pinch->setMinimumScale(0.5);
+ pinch->setMaximumScale(1.5);
+
+ QCOMPARE(scaleMinSpy.count(),1);
+ QCOMPARE(scaleMaxSpy.count(),1);
+
+ // minimum and maximum rotation properties
+ QSignalSpy rotMinSpy(pinch, SIGNAL(minimumRotationChanged()));
+ QSignalSpy rotMaxSpy(pinch, SIGNAL(maximumRotationChanged()));
+
+ QCOMPARE(pinch->minimumRotation(), 0.0);
+ QCOMPARE(pinch->maximumRotation(), 90.0);
+
+ pinch->setMinimumRotation(-90.0);
+ pinch->setMaximumRotation(45.0);
+
+ QCOMPARE(pinch->minimumRotation(), -90.0);
+ QCOMPARE(pinch->maximumRotation(), 45.0);
+
+ QCOMPARE(rotMinSpy.count(),1);
+ QCOMPARE(rotMaxSpy.count(),1);
+
+ pinch->setMinimumRotation(-90.0);
+ pinch->setMaximumRotation(45.0);
+
+ QCOMPARE(rotMinSpy.count(),1);
+ QCOMPARE(rotMaxSpy.count(),1);
+
+ delete canvas;
+}
+
+QTouchEvent::TouchPoint makeTouchPoint(int id, QPoint p, QSGView *v, QSGItem *i)
+{
+ QTouchEvent::TouchPoint touchPoint(id);
+ touchPoint.setPos(i->mapFromScene(p));
+ touchPoint.setScreenPos(v->mapToGlobal(p));
+ touchPoint.setScenePos(p);
+ return touchPoint;
+}
+
+void tst_QSGPinchArea::scale()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pinchproperties.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QTest::qWaitForWindowShown(canvas);
+ QVERIFY(canvas->rootObject() != 0);
+ qApp->processEvents();
+
+ QSGPinchArea *pinchArea = canvas->rootObject()->findChild<QSGPinchArea*>("pincharea");
+ QSGPinch *pinch = pinchArea->pinch();
+ QVERIFY(pinchArea != 0);
+ QVERIFY(pinch != 0);
+
+ QSGItem *root = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(root != 0);
+
+ // target
+ QSGItem *blackRect = canvas->rootObject()->findChild<QSGItem*>("blackrect");
+ QVERIFY(blackRect != 0);
+
+ QPoint p1(80, 80);
+ QPoint p2(100, 100);
+
+ QTest::touchEvent(canvas).press(0, p1);
+ QTest::touchEvent(canvas).stationary(0).press(1, p2);
+ p1 -= QPoint(10,10);
+ p2 += QPoint(10,10);
+ QTest::touchEvent(canvas).move(0, p1).move(1, p2);
+
+ QCOMPARE(root->property("scale").toReal(), 1.0);
+
+ p1 -= QPoint(10,10);
+ p2 += QPoint(10,10);
+ QTest::touchEvent(canvas).move(0, p1).move(1, p2);
+
+ QCOMPARE(root->property("scale").toReal(), 1.5);
+ QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
+ QCOMPARE(blackRect->scale(), 1.5);
+
+ // scale beyond bound
+ p1 -= QPoint(50,50);
+ p2 += QPoint(50,50);
+ QTest::touchEvent(canvas).move(0, p1).move(1, p2);
+
+ QCOMPARE(blackRect->scale(), 2.0);
+
+ QTest::touchEvent(canvas).release(0, p1).release(1, p2);
+
+ delete canvas;
+}
+
+void tst_QSGPinchArea::pan()
+{
+ QSGView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pinchproperties.qml"));
+ canvas->show();
+ canvas->setFocus();
+ QTest::qWaitForWindowShown(canvas);
+ QVERIFY(canvas->rootObject() != 0);
+ qApp->processEvents();
+
+ QSGPinchArea *pinchArea = canvas->rootObject()->findChild<QSGPinchArea*>("pincharea");
+ QSGPinch *pinch = pinchArea->pinch();
+ QVERIFY(pinchArea != 0);
+ QVERIFY(pinch != 0);
+
+ QSGItem *root = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(root != 0);
+
+ // target
+ QSGItem *blackRect = canvas->rootObject()->findChild<QSGItem*>("blackrect");
+ QVERIFY(blackRect != 0);
+
+ QPoint p1(80, 80);
+ QPoint p2(100, 100);
+
+ QTest::touchEvent(canvas).press(0, p1);
+ QTest::touchEvent(canvas).stationary(0).press(1, p2);
+ p1 += QPoint(10,10);
+ p2 += QPoint(10,10);
+ QTest::touchEvent(canvas).move(0, p1).move(1, p2);
+
+ QCOMPARE(root->property("scale").toReal(), 1.0);
+
+ p1 += QPoint(10,10);
+ p2 += QPoint(10,10);
+ QTest::touchEvent(canvas).move(0, p1).move(1, p2);
+
+ QCOMPARE(root->property("center").toPointF(), QPointF(60, 60)); // blackrect is at 50,50
+
+ QCOMPARE(blackRect->x(), 60.0);
+ QCOMPARE(blackRect->y(), 60.0);
+
+ // pan x beyond bound
+ p1 += QPoint(100,100);
+ p2 += QPoint(100,100);
+ QTest::touchEvent(canvas).move(0, p1).move(1, p2);
+
+ QCOMPARE(blackRect->x(), 140.0);
+ QCOMPARE(blackRect->y(), 160.0);
+
+ QTest::touchEvent(canvas).release(0, p1).release(1, p2);
+
+ delete canvas;
+}
+
+QSGView *tst_QSGPinchArea::createView()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setAttribute(Qt::WA_AcceptTouchEvents);
+ canvas->setFixedSize(240,320);
+
+ return canvas;
+}
+
+QTEST_MAIN(tst_QSGPinchArea)
+
+#include "tst_qsgpincharea.moc"
diff --git a/tests/auto/declarative/qsgpositioners/data/flow-testimplicitsize.qml b/tests/auto/declarative/qsgpositioners/data/flow-testimplicitsize.qml
new file mode 100644
index 0000000000..c32b78676c
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/flow-testimplicitsize.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 300; height: 200;
+
+ property int flowLayout: 1
+
+ Flow {
+ objectName: "flow"
+ layoutDirection: (flowLayout == 2) ? Qt.RightToLeft : Qt.LeftToRight
+ flow: (flowLayout == 1) ? Flow.TopToBottom : Flow.LeftToRight;
+
+ spacing: 20
+ anchors.horizontalCenter: parent.horizontalCenter
+ Rectangle { color: "red"; width: 100; height: 50 }
+ Rectangle { color: "blue"; width: 100; height: 50 }
+ }
+}
+
diff --git a/tests/auto/declarative/qsgpositioners/data/flowtest-toptobottom.qml b/tests/auto/declarative/qsgpositioners/data/flowtest-toptobottom.qml
new file mode 100644
index 0000000000..a7d3ee13c7
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/flowtest-toptobottom.qml
@@ -0,0 +1,44 @@
+import QtQuick 2.0
+
+Item {
+ height: 90
+ width: 480
+ property bool testRightToLeft: false
+
+ Flow {
+ objectName: "flow"
+ height: parent.height
+ layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight
+ flow: Flow.TopToBottom
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "green"
+ width: 20
+ height: 50
+ }
+ Rectangle {
+ objectName: "three"
+ color: "blue"
+ width: 50
+ height: 20
+ }
+ Rectangle {
+ objectName: "four"
+ color: "cyan"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "five"
+ color: "magenta"
+ width: 10
+ height: 10
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/flowtest.qml b/tests/auto/declarative/qsgpositioners/data/flowtest.qml
new file mode 100644
index 0000000000..40b042dd79
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/flowtest.qml
@@ -0,0 +1,43 @@
+import QtQuick 2.0
+
+Item {
+ width: 90
+ height: 480
+ property bool testRightToLeft: false
+
+ Flow {
+ objectName: "flow"
+ width: parent.width
+ layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "green"
+ width: 20
+ height: 50
+ }
+ Rectangle {
+ objectName: "three"
+ color: "blue"
+ width: 50
+ height: 20
+ }
+ Rectangle {
+ objectName: "four"
+ color: "cyan"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "five"
+ color: "magenta"
+ width: 10
+ height: 10
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/grid-animated.qml b/tests/auto/declarative/qsgpositioners/data/grid-animated.qml
new file mode 100644
index 0000000000..56e8f26953
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/grid-animated.qml
@@ -0,0 +1,64 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ property bool testRightToLeft: true
+
+ Grid {
+ objectName: "grid"
+ columns: 3
+ layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight
+ add: Transition {
+ NumberAnimation {
+ properties: "x,y";
+ }
+ }
+ move: Transition {
+ NumberAnimation {
+ properties: "x,y";
+ }
+ }
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ x: -100
+ y: -100
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ x: -100
+ y: -100
+ opacity: 0
+ color: "green"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "three"
+ color: "blue"
+ x: -100
+ y: -100
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "four"
+ color: "cyan"
+ x: -100
+ y: -100
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "five"
+ color: "magenta"
+ x: -100
+ y: -100
+ width: 50
+ height: 50
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/grid-spacing.qml b/tests/auto/declarative/qsgpositioners/data/grid-spacing.qml
new file mode 100644
index 0000000000..535a39037f
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/grid-spacing.qml
@@ -0,0 +1,41 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ Grid {
+ objectName: "grid"
+ columns: 3
+ spacing: 4
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "green"
+ width: 20
+ height: 50
+ }
+ Rectangle {
+ objectName: "three"
+ color: "blue"
+ width: 50
+ height: 20
+ }
+ Rectangle {
+ objectName: "four"
+ color: "cyan"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "five"
+ color: "magenta"
+ width: 10
+ height: 10
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/grid-toptobottom.qml b/tests/auto/declarative/qsgpositioners/data/grid-toptobottom.qml
new file mode 100644
index 0000000000..45559aab5d
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/grid-toptobottom.qml
@@ -0,0 +1,41 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ Grid {
+ objectName: "grid"
+ rows: 3
+ flow: Grid.TopToBottom
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "green"
+ width: 20
+ height: 50
+ }
+ Rectangle {
+ objectName: "three"
+ color: "blue"
+ width: 50
+ height: 20
+ }
+ Rectangle {
+ objectName: "four"
+ color: "cyan"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "five"
+ color: "magenta"
+ width: 10
+ height: 10
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/gridtest.qml b/tests/auto/declarative/qsgpositioners/data/gridtest.qml
new file mode 100644
index 0000000000..50bec1377b
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/gridtest.qml
@@ -0,0 +1,42 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ property bool testRightToLeft: false
+ Grid {
+ layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight
+ objectName: "grid"
+ columns: 3
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "green"
+ width: 20
+ height: 50
+ }
+ Rectangle {
+ objectName: "three"
+ color: "blue"
+ width: 30
+ height: 20
+ }
+ Rectangle {
+ objectName: "four"
+ color: "cyan"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "five"
+ color: "magenta"
+ width: 10
+ height: 10
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/gridzerocolumns.qml b/tests/auto/declarative/qsgpositioners/data/gridzerocolumns.qml
new file mode 100644
index 0000000000..a252f279c3
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/gridzerocolumns.qml
@@ -0,0 +1,40 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ Grid {
+ objectName: "grid"
+ columns: 0
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "green"
+ width: 20
+ height: 50
+ }
+ Rectangle {
+ objectName: "three"
+ color: "blue"
+ width: 50
+ height: 20
+ }
+ Rectangle {
+ objectName: "four"
+ color: "cyan"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "five"
+ color: "magenta"
+ width: 10
+ height: 10
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/horizontal-animated.qml b/tests/auto/declarative/qsgpositioners/data/horizontal-animated.qml
new file mode 100644
index 0000000000..d19cc46c8b
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/horizontal-animated.qml
@@ -0,0 +1,44 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ property bool testRightToLeft: false
+
+ Row {
+ objectName: "row"
+ layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight
+ add: Transition {
+ NumberAnimation {
+ properties: "x";
+ }
+ }
+ move: Transition {
+ NumberAnimation {
+ properties: "x";
+ }
+ }
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ x: -100;
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "blue"
+ x: -100;
+ opacity: 0
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "three"
+ x: -100;
+ color: "green"
+ width: 50
+ height: 50
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/horizontal-spacing.qml b/tests/auto/declarative/qsgpositioners/data/horizontal-spacing.qml
new file mode 100644
index 0000000000..c6ff75ac6b
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/horizontal-spacing.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ property bool testRightToLeft: false
+
+ Row {
+ objectName: "row"
+ spacing: 10
+ layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "red"
+ width: 20
+ height: 10
+ }
+ Rectangle {
+ objectName: "three"
+ color: "red"
+ width: 40
+ height: 20
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/horizontal.qml b/tests/auto/declarative/qsgpositioners/data/horizontal.qml
new file mode 100644
index 0000000000..235ee78c9b
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/horizontal.qml
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ property bool testRightToLeft: false
+ Row {
+ objectName: "row"
+ layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "red"
+ width: 20
+ height: 10
+ }
+ Rectangle {
+ objectName: "three"
+ color: "red"
+ width: 40
+ height: 20
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/propertychangestest.qml b/tests/auto/declarative/qsgpositioners/data/propertychangestest.qml
new file mode 100644
index 0000000000..c9fd62b012
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/propertychangestest.qml
@@ -0,0 +1,39 @@
+import QtQuick 2.0
+
+Grid {
+ id: myGrid
+
+ width: 270
+ height: 270
+ x: 3
+ y: 3
+ columns: 4
+ spacing: 3
+
+ add: columnTransition
+ move: columnTransition
+
+ Repeater {
+ model: 20
+ Rectangle { color: "black"; width: 50; height: 50 }
+ }
+
+ data: [
+ Transition {
+ id: rowTransition
+ objectName: "rowTransition"
+ NumberAnimation {
+ properties: "x,y";
+ easing.type: "OutInCubic"
+ }
+ },
+ Transition {
+ id: columnTransition
+ objectName: "columnTransition"
+ NumberAnimation {
+ properties: "x,y";
+ easing.type: "OutInCubic"
+ }
+ }
+ ]
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/repeatertest.qml b/tests/auto/declarative/qsgpositioners/data/repeatertest.qml
new file mode 100644
index 0000000000..d90e1cf160
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/repeatertest.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ Row {
+ Repeater{ model: 3;
+ delegate: Component {
+ Rectangle {
+ color: "red"
+ width: 50
+ height: 50
+ z: {if(index == 0){2;}else if(index == 1){1;} else{3;}}
+ objectName: {if(index == 0){"one";}else if(index == 1){"two";} else{"three";}}
+ }
+ }
+ }
+ }
+
+ //This crashed once (QTBUG-16959) because the repeater ended up on the end of the list
+ //If this grid just instantiates without crashing, then it has not regressed.
+ Grid {
+ id: grid
+ rows: 2
+ flow: Grid.TopToBottom
+
+ Repeater {
+ model: 13
+ Rectangle {
+ color: "goldenrod"
+ width: 100
+ height: 100
+ radius: 10
+ border.width: 1
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/vertical-animated.qml b/tests/auto/declarative/qsgpositioners/data/vertical-animated.qml
new file mode 100644
index 0000000000..69f1b7eb25
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/vertical-animated.qml
@@ -0,0 +1,41 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ Column {
+ objectName: "column"
+ add: Transition {
+ NumberAnimation {
+ properties: "y";
+ }
+ }
+ move: Transition {
+ NumberAnimation {
+ properties: "y";
+ }
+ }
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ y: -100
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "blue"
+ y: -100
+ opacity: 0
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "three"
+ color: "red"
+ y: -100
+ width: 50
+ height: 50
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/vertical-spacing.qml b/tests/auto/declarative/qsgpositioners/data/vertical-spacing.qml
new file mode 100644
index 0000000000..7087961651
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/vertical-spacing.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ Column {
+ objectName: "column"
+ spacing: 10
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "red"
+ width: 20
+ height: 10
+ }
+ Rectangle {
+ objectName: "three"
+ color: "red"
+ width: 40
+ height: 20
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/data/vertical.qml b/tests/auto/declarative/qsgpositioners/data/vertical.qml
new file mode 100644
index 0000000000..0c3a81f008
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/data/vertical.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+Item {
+ width: 640
+ height: 480
+ Column {
+ objectName: "column"
+ Rectangle {
+ objectName: "one"
+ color: "red"
+ width: 50
+ height: 50
+ }
+ Rectangle {
+ objectName: "two"
+ color: "red"
+ width: 20
+ height: 10
+ }
+ Rectangle {
+ objectName: "three"
+ color: "red"
+ width: 40
+ height: 20
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgpositioners/qsgpositioners.pro b/tests/auto/declarative/qsgpositioners/qsgpositioners.pro
new file mode 100644
index 0000000000..f1ba7c0505
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/qsgpositioners.pro
@@ -0,0 +1,15 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative
+SOURCES += tst_qsgpositioners.cpp
+macx:CONFIG -= app_bundle
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgpositioners/tst_qsgpositioners.cpp b/tests/auto/declarative/qsgpositioners/tst_qsgpositioners.cpp
new file mode 100644
index 0000000000..4e29b65d16
--- /dev/null
+++ b/tests/auto/declarative/qsgpositioners/tst_qsgpositioners.cpp
@@ -0,0 +1,1268 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtTest/QtTest>
+#include <private/qlistmodelinterface_p.h>
+#include <qsgview.h>
+#include <qdeclarativeengine.h>
+#include <private/qsgrectangle_p.h>
+#include <private/qsgpositioners_p.h>
+#include <private/qdeclarativetransition_p.h>
+#include <private/qsgitem_p.h>
+#include <qdeclarativeexpression.h>
+#include <QtGui/qgraphicswidget.h>
+#include "../../../shared/util.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_qsgpositioners : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qsgpositioners();
+
+private slots:
+ void test_horizontal();
+ void test_horizontal_rtl();
+ void test_horizontal_spacing();
+ void test_horizontal_spacing_rightToLeft();
+ void test_horizontal_animated();
+ void test_horizontal_animated_rightToLeft();
+ void test_vertical();
+ void test_vertical_spacing();
+ void test_vertical_animated();
+ void test_grid();
+ void test_grid_topToBottom();
+ void test_grid_rightToLeft();
+ void test_grid_spacing();
+ void test_grid_animated();
+ void test_grid_animated_rightToLeft();
+ void test_grid_zero_columns();
+ void test_propertychanges();
+ void test_repeater();
+ void test_flow();
+ void test_flow_rightToLeft();
+ void test_flow_topToBottom();
+ void test_flow_resize();
+ void test_flow_resize_rightToLeft();
+ void test_flow_implicit_resize();
+ void test_conflictinganchors();
+ void test_mirroring();
+private:
+ QSGView *createView(const QString &filename);
+};
+
+tst_qsgpositioners::tst_qsgpositioners()
+{
+}
+
+void tst_qsgpositioners::test_horizontal()
+{
+ QSGView *canvas = createView(SRCDIR "/data/horizontal.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", false);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 50.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 70.0);
+ QCOMPARE(three->y(), 0.0);
+
+ QSGItem *row = canvas->rootObject()->findChild<QSGItem*>("row");
+ QCOMPARE(row->width(), 110.0);
+ QCOMPARE(row->height(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_horizontal_rtl()
+{
+ QSGView *canvas = createView(SRCDIR "/data/horizontal.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", true);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+
+ QCOMPARE(one->x(), 60.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 40.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 0.0);
+ QCOMPARE(three->y(), 0.0);
+
+ QSGItem *row = canvas->rootObject()->findChild<QSGItem*>("row");
+ QCOMPARE(row->width(), 110.0);
+ QCOMPARE(row->height(), 50.0);
+
+ // Change the width of the row and check that items stay to the right
+ row->setWidth(200);
+ QCOMPARE(one->x(), 150.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 130.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 90.0);
+ QCOMPARE(three->y(), 0.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_horizontal_spacing()
+{
+ QSGView *canvas = createView(SRCDIR "/data/horizontal-spacing.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", false);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 60.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 90.0);
+ QCOMPARE(three->y(), 0.0);
+
+ QSGItem *row = canvas->rootObject()->findChild<QSGItem*>("row");
+ QCOMPARE(row->width(), 130.0);
+ QCOMPARE(row->height(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_horizontal_spacing_rightToLeft()
+{
+ QSGView *canvas = createView(SRCDIR "/data/horizontal-spacing.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", true);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+
+ QCOMPARE(one->x(), 80.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 50.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 00.0);
+ QCOMPARE(three->y(), 0.0);
+
+ QSGItem *row = canvas->rootObject()->findChild<QSGItem*>("row");
+ QCOMPARE(row->width(), 130.0);
+ QCOMPARE(row->height(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_horizontal_animated()
+{
+ QSGView *canvas = createView(SRCDIR "/data/horizontal-animated.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", false);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+
+ //Note that they animate in
+ QCOMPARE(one->x(), -100.0);
+ QCOMPARE(two->x(), -100.0);
+ QCOMPARE(three->x(), -100.0);
+
+ QSGItem *row = canvas->rootObject()->findChild<QSGItem*>("row");
+ QVERIFY(row);
+ QCOMPARE(row->width(), 100.0);
+ QCOMPARE(row->height(), 50.0);
+
+ //QTRY_COMPARE used instead of waiting for the expected time of animation completion
+ //Note that this means the duration of the animation is NOT tested
+
+ QTRY_COMPARE(one->x(), 0.0);
+ QTRY_COMPARE(one->y(), 0.0);
+ QTRY_COMPARE(two->opacity(), 0.0);
+ QTRY_COMPARE(two->x(), -100.0);//Not 'in' yet
+ QTRY_COMPARE(two->y(), 0.0);
+ QTRY_COMPARE(three->x(), 50.0);
+ QTRY_COMPARE(three->y(), 0.0);
+
+ //Add 'two'
+ two->setOpacity(1.0);
+ QCOMPARE(two->opacity(), 1.0);
+
+ // New size should be immediate
+ QCOMPARE(row->width(), 150.0);
+ QCOMPARE(row->height(), 50.0);
+
+ QTest::qWait(0);//Let the animation start
+ QCOMPARE(two->x(), -100.0);
+ QCOMPARE(three->x(), 50.0);
+
+ QTRY_COMPARE(two->x(), 50.0);
+ QTRY_COMPARE(three->x(), 100.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_horizontal_animated_rightToLeft()
+{
+ QSGView *canvas = createView(SRCDIR "/data/horizontal-animated.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", true);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+
+ //Note that they animate in
+ QCOMPARE(one->x(), -100.0);
+ QCOMPARE(two->x(), -100.0);
+ QCOMPARE(three->x(), -100.0);
+
+ QSGItem *row = canvas->rootObject()->findChild<QSGItem*>("row");
+ QVERIFY(row);
+ QCOMPARE(row->width(), 100.0);
+ QCOMPARE(row->height(), 50.0);
+
+ //QTRY_COMPARE used instead of waiting for the expected time of animation completion
+ //Note that this means the duration of the animation is NOT tested
+
+ QTRY_COMPARE(one->x(), 50.0);
+ QTRY_COMPARE(one->y(), 0.0);
+ QTRY_COMPARE(two->opacity(), 0.0);
+ QTRY_COMPARE(two->x(), -100.0);//Not 'in' yet
+ QTRY_COMPARE(two->y(), 0.0);
+ QTRY_COMPARE(three->x(), 0.0);
+ QTRY_COMPARE(three->y(), 0.0);
+
+ //Add 'two'
+ two->setOpacity(1.0);
+ QCOMPARE(two->opacity(), 1.0);
+
+ // New size should be immediate
+ QCOMPARE(row->width(), 150.0);
+ QCOMPARE(row->height(), 50.0);
+
+ QTest::qWait(0);//Let the animation start
+ QCOMPARE(one->x(), 50.0);
+ QCOMPARE(two->x(), -100.0);
+
+ QTRY_COMPARE(one->x(), 100.0);
+ QTRY_COMPARE(two->x(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_vertical()
+{
+ QSGView *canvas = createView(SRCDIR "/data/vertical.qml");
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 0.0);
+ QCOMPARE(two->y(), 50.0);
+ QCOMPARE(three->x(), 0.0);
+ QCOMPARE(three->y(), 60.0);
+
+ QSGItem *column = canvas->rootObject()->findChild<QSGItem*>("column");
+ QVERIFY(column);
+ QCOMPARE(column->height(), 80.0);
+ QCOMPARE(column->width(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_vertical_spacing()
+{
+ QSGView *canvas = createView(SRCDIR "/data/vertical-spacing.qml");
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 0.0);
+ QCOMPARE(two->y(), 60.0);
+ QCOMPARE(three->x(), 0.0);
+ QCOMPARE(three->y(), 80.0);
+
+ QSGItem *column = canvas->rootObject()->findChild<QSGItem*>("column");
+ QCOMPARE(column->height(), 100.0);
+ QCOMPARE(column->width(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_vertical_animated()
+{
+ QSGView *canvas = createView(SRCDIR "/data/vertical-animated.qml");
+
+ //Note that they animate in
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QCOMPARE(one->y(), -100.0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QCOMPARE(two->y(), -100.0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QCOMPARE(three->y(), -100.0);
+
+ QSGItem *column = canvas->rootObject()->findChild<QSGItem*>("column");
+ QVERIFY(column);
+ QCOMPARE(column->height(), 100.0);
+ QCOMPARE(column->width(), 50.0);
+
+ //QTRY_COMPARE used instead of waiting for the expected time of animation completion
+ //Note that this means the duration of the animation is NOT tested
+
+ QTRY_COMPARE(one->y(), 0.0);
+ QTRY_COMPARE(one->x(), 0.0);
+ QTRY_COMPARE(two->opacity(), 0.0);
+ QTRY_COMPARE(two->y(), -100.0);//Not 'in' yet
+ QTRY_COMPARE(two->x(), 0.0);
+ QTRY_COMPARE(three->y(), 50.0);
+ QTRY_COMPARE(three->x(), 0.0);
+
+ //Add 'two'
+ two->setOpacity(1.0);
+ QTRY_COMPARE(two->opacity(), 1.0);
+ QCOMPARE(column->height(), 150.0);
+ QCOMPARE(column->width(), 50.0);
+ QTest::qWait(0);//Let the animation start
+ QCOMPARE(two->y(), -100.0);
+ QCOMPARE(three->y(), 50.0);
+
+ QTRY_COMPARE(two->y(), 50.0);
+ QTRY_COMPARE(three->y(), 100.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_grid()
+{
+ QSGView *canvas = createView(SRCDIR "/data/gridtest.qml");
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 50.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 70.0);
+ QCOMPARE(three->y(), 0.0);
+ QCOMPARE(four->x(), 0.0);
+ QCOMPARE(four->y(), 50.0);
+ QCOMPARE(five->x(), 50.0);
+ QCOMPARE(five->y(), 50.0);
+
+ QSGGrid *grid = canvas->rootObject()->findChild<QSGGrid*>("grid");
+ QCOMPARE(grid->flow(), QSGGrid::LeftToRight);
+ QCOMPARE(grid->width(), 100.0);
+ QCOMPARE(grid->height(), 100.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_grid_topToBottom()
+{
+ QSGView *canvas = createView(SRCDIR "/data/grid-toptobottom.qml");
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 0.0);
+ QCOMPARE(two->y(), 50.0);
+ QCOMPARE(three->x(), 0.0);
+ QCOMPARE(three->y(), 100.0);
+ QCOMPARE(four->x(), 50.0);
+ QCOMPARE(four->y(), 0.0);
+ QCOMPARE(five->x(), 50.0);
+ QCOMPARE(five->y(), 50.0);
+
+ QSGGrid *grid = canvas->rootObject()->findChild<QSGGrid*>("grid");
+ QCOMPARE(grid->flow(), QSGGrid::TopToBottom);
+ QCOMPARE(grid->width(), 100.0);
+ QCOMPARE(grid->height(), 120.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_grid_rightToLeft()
+{
+ QSGView *canvas = createView(SRCDIR "/data/gridtest.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", true);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+
+ QCOMPARE(one->x(), 50.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 30.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 0.0);
+ QCOMPARE(three->y(), 0.0);
+ QCOMPARE(four->x(), 50.0);
+ QCOMPARE(four->y(), 50.0);
+ QCOMPARE(five->x(), 40.0);
+ QCOMPARE(five->y(), 50.0);
+
+ QSGGrid *grid = canvas->rootObject()->findChild<QSGGrid*>("grid");
+ QCOMPARE(grid->layoutDirection(), Qt::RightToLeft);
+ QCOMPARE(grid->width(), 100.0);
+ QCOMPARE(grid->height(), 100.0);
+
+ // Change the width of the grid and check that items stay to the right
+ grid->setWidth(200);
+ QCOMPARE(one->x(), 150.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 130.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 100.0);
+ QCOMPARE(three->y(), 0.0);
+ QCOMPARE(four->x(), 150.0);
+ QCOMPARE(four->y(), 50.0);
+ QCOMPARE(five->x(), 140.0);
+ QCOMPARE(five->y(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_grid_spacing()
+{
+ QSGView *canvas = createView(SRCDIR "/data/grid-spacing.qml");
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 54.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 78.0);
+ QCOMPARE(three->y(), 0.0);
+ QCOMPARE(four->x(), 0.0);
+ QCOMPARE(four->y(), 54.0);
+ QCOMPARE(five->x(), 54.0);
+ QCOMPARE(five->y(), 54.0);
+
+ QSGItem *grid = canvas->rootObject()->findChild<QSGItem*>("grid");
+ QCOMPARE(grid->width(), 128.0);
+ QCOMPARE(grid->height(), 104.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_grid_animated()
+{
+ QSGView *canvas = createView(SRCDIR "/data/grid-animated.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", false);
+
+ //Note that all animate in
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QCOMPARE(one->x(), -100.0);
+ QCOMPARE(one->y(), -100.0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QCOMPARE(two->x(), -100.0);
+ QCOMPARE(two->y(), -100.0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QCOMPARE(three->x(), -100.0);
+ QCOMPARE(three->y(), -100.0);
+
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QCOMPARE(four->x(), -100.0);
+ QCOMPARE(four->y(), -100.0);
+
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+ QCOMPARE(five->x(), -100.0);
+ QCOMPARE(five->y(), -100.0);
+
+ QSGItem *grid = canvas->rootObject()->findChild<QSGItem*>("grid");
+ QVERIFY(grid);
+ QCOMPARE(grid->width(), 150.0);
+ QCOMPARE(grid->height(), 100.0);
+
+ //QTRY_COMPARE used instead of waiting for the expected time of animation completion
+ //Note that this means the duration of the animation is NOT tested
+
+ QTRY_COMPARE(one->y(), 0.0);
+ QTRY_COMPARE(one->x(), 0.0);
+ QTRY_COMPARE(two->opacity(), 0.0);
+ QTRY_COMPARE(two->y(), -100.0);
+ QTRY_COMPARE(two->x(), -100.0);
+ QTRY_COMPARE(three->y(), 0.0);
+ QTRY_COMPARE(three->x(), 50.0);
+ QTRY_COMPARE(four->y(), 0.0);
+ QTRY_COMPARE(four->x(), 100.0);
+ QTRY_COMPARE(five->y(), 50.0);
+ QTRY_COMPARE(five->x(), 0.0);
+
+ //Add 'two'
+ two->setOpacity(1.0);
+ QCOMPARE(two->opacity(), 1.0);
+ QCOMPARE(grid->width(), 150.0);
+ QCOMPARE(grid->height(), 100.0);
+ QTest::qWait(0);//Let the animation start
+ QCOMPARE(two->x(), -100.0);
+ QCOMPARE(two->y(), -100.0);
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(three->x(), 50.0);
+ QCOMPARE(three->y(), 0.0);
+ QCOMPARE(four->x(), 100.0);
+ QCOMPARE(four->y(), 0.0);
+ QCOMPARE(five->x(), 0.0);
+ QCOMPARE(five->y(), 50.0);
+ //Let the animation complete
+ QTRY_COMPARE(two->x(), 50.0);
+ QTRY_COMPARE(two->y(), 0.0);
+ QTRY_COMPARE(one->x(), 0.0);
+ QTRY_COMPARE(one->y(), 0.0);
+ QTRY_COMPARE(three->x(), 100.0);
+ QTRY_COMPARE(three->y(), 0.0);
+ QTRY_COMPARE(four->x(), 0.0);
+ QTRY_COMPARE(four->y(), 50.0);
+ QTRY_COMPARE(five->x(), 50.0);
+ QTRY_COMPARE(five->y(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_grid_animated_rightToLeft()
+{
+ QSGView *canvas = createView(SRCDIR "/data/grid-animated.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", true);
+
+ //Note that all animate in
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QCOMPARE(one->x(), -100.0);
+ QCOMPARE(one->y(), -100.0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QCOMPARE(two->x(), -100.0);
+ QCOMPARE(two->y(), -100.0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QCOMPARE(three->x(), -100.0);
+ QCOMPARE(three->y(), -100.0);
+
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QCOMPARE(four->x(), -100.0);
+ QCOMPARE(four->y(), -100.0);
+
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+ QCOMPARE(five->x(), -100.0);
+ QCOMPARE(five->y(), -100.0);
+
+ QSGItem *grid = canvas->rootObject()->findChild<QSGItem*>("grid");
+ QVERIFY(grid);
+ QCOMPARE(grid->width(), 150.0);
+ QCOMPARE(grid->height(), 100.0);
+
+ //QTRY_COMPARE used instead of waiting for the expected time of animation completion
+ //Note that this means the duration of the animation is NOT tested
+
+ QTRY_COMPARE(one->y(), 0.0);
+ QTRY_COMPARE(one->x(), 100.0);
+ QTRY_COMPARE(two->opacity(), 0.0);
+ QTRY_COMPARE(two->y(), -100.0);
+ QTRY_COMPARE(two->x(), -100.0);
+ QTRY_COMPARE(three->y(), 0.0);
+ QTRY_COMPARE(three->x(), 50.0);
+ QTRY_COMPARE(four->y(), 0.0);
+ QTRY_COMPARE(four->x(), 0.0);
+ QTRY_COMPARE(five->y(), 50.0);
+ QTRY_COMPARE(five->x(), 100.0);
+
+ //Add 'two'
+ two->setOpacity(1.0);
+ QCOMPARE(two->opacity(), 1.0);
+ QCOMPARE(grid->width(), 150.0);
+ QCOMPARE(grid->height(), 100.0);
+ QTest::qWait(0);//Let the animation start
+ QCOMPARE(two->x(), -100.0);
+ QCOMPARE(two->y(), -100.0);
+ QCOMPARE(one->x(), 100.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(three->x(), 50.0);
+ QCOMPARE(three->y(), 0.0);
+ QCOMPARE(four->x(), 0.0);
+ QCOMPARE(four->y(), 0.0);
+ QCOMPARE(five->x(), 100.0);
+ QCOMPARE(five->y(), 50.0);
+ //Let the animation complete
+ QTRY_COMPARE(two->x(), 50.0);
+ QTRY_COMPARE(two->y(), 0.0);
+ QTRY_COMPARE(one->x(), 100.0);
+ QTRY_COMPARE(one->y(), 0.0);
+ QTRY_COMPARE(three->x(), 0.0);
+ QTRY_COMPARE(three->y(), 0.0);
+ QTRY_COMPARE(four->x(), 100.0);
+ QTRY_COMPARE(four->y(), 50.0);
+ QTRY_COMPARE(five->x(), 50.0);
+ QTRY_COMPARE(five->y(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_grid_zero_columns()
+{
+ QSGView *canvas = createView(SRCDIR "/data/gridzerocolumns.qml");
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 50.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 70.0);
+ QCOMPARE(three->y(), 0.0);
+ QCOMPARE(four->x(), 120.0);
+ QCOMPARE(four->y(), 0.0);
+ QCOMPARE(five->x(), 0.0);
+ QCOMPARE(five->y(), 50.0);
+
+ QSGItem *grid = canvas->rootObject()->findChild<QSGItem*>("grid");
+ QCOMPARE(grid->width(), 170.0);
+ QCOMPARE(grid->height(), 60.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_propertychanges()
+{
+ QSGView *canvas = createView(SRCDIR "/data/propertychangestest.qml");
+
+ QSGGrid *grid = qobject_cast<QSGGrid*>(canvas->rootObject());
+ QVERIFY(grid != 0);
+ QDeclarativeTransition *rowTransition = canvas->rootObject()->findChild<QDeclarativeTransition*>("rowTransition");
+ QDeclarativeTransition *columnTransition = canvas->rootObject()->findChild<QDeclarativeTransition*>("columnTransition");
+
+ QSignalSpy addSpy(grid, SIGNAL(addChanged()));
+ QSignalSpy moveSpy(grid, SIGNAL(moveChanged()));
+ QSignalSpy columnsSpy(grid, SIGNAL(columnsChanged()));
+ QSignalSpy rowsSpy(grid, SIGNAL(rowsChanged()));
+
+ QVERIFY(grid);
+ QVERIFY(rowTransition);
+ QVERIFY(columnTransition);
+ QCOMPARE(grid->add(), columnTransition);
+ QCOMPARE(grid->move(), columnTransition);
+ QCOMPARE(grid->columns(), 4);
+ QCOMPARE(grid->rows(), -1);
+
+ grid->setAdd(rowTransition);
+ grid->setMove(rowTransition);
+ QCOMPARE(grid->add(), rowTransition);
+ QCOMPARE(grid->move(), rowTransition);
+ QCOMPARE(addSpy.count(),1);
+ QCOMPARE(moveSpy.count(),1);
+
+ grid->setAdd(rowTransition);
+ grid->setMove(rowTransition);
+ QCOMPARE(addSpy.count(),1);
+ QCOMPARE(moveSpy.count(),1);
+
+ grid->setAdd(0);
+ grid->setMove(0);
+ QCOMPARE(addSpy.count(),2);
+ QCOMPARE(moveSpy.count(),2);
+
+ grid->setColumns(-1);
+ grid->setRows(3);
+ QCOMPARE(grid->columns(), -1);
+ QCOMPARE(grid->rows(), 3);
+ QCOMPARE(columnsSpy.count(),1);
+ QCOMPARE(rowsSpy.count(),1);
+
+ grid->setColumns(-1);
+ grid->setRows(3);
+ QCOMPARE(columnsSpy.count(),1);
+ QCOMPARE(rowsSpy.count(),1);
+
+ grid->setColumns(2);
+ grid->setRows(2);
+ QCOMPARE(columnsSpy.count(),2);
+ QCOMPARE(rowsSpy.count(),2);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_repeater()
+{
+ QSGView *canvas = createView(SRCDIR "/data/repeatertest.qml");
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 50.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 100.0);
+ QCOMPARE(three->y(), 0.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_flow()
+{
+ QSGView *canvas = createView(SRCDIR "/data/flowtest.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", false);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 50.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 0.0);
+ QCOMPARE(three->y(), 50.0);
+ QCOMPARE(four->x(), 0.0);
+ QCOMPARE(four->y(), 70.0);
+ QCOMPARE(five->x(), 50.0);
+ QCOMPARE(five->y(), 70.0);
+
+ QSGItem *flow = canvas->rootObject()->findChild<QSGItem*>("flow");
+ QVERIFY(flow);
+ QCOMPARE(flow->width(), 90.0);
+ QCOMPARE(flow->height(), 120.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_flow_rightToLeft()
+{
+ QSGView *canvas = createView(SRCDIR "/data/flowtest.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", true);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+
+ QCOMPARE(one->x(), 40.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 20.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 40.0);
+ QCOMPARE(three->y(), 50.0);
+ QCOMPARE(four->x(), 40.0);
+ QCOMPARE(four->y(), 70.0);
+ QCOMPARE(five->x(), 30.0);
+ QCOMPARE(five->y(), 70.0);
+
+ QSGItem *flow = canvas->rootObject()->findChild<QSGItem*>("flow");
+ QVERIFY(flow);
+ QCOMPARE(flow->width(), 90.0);
+ QCOMPARE(flow->height(), 120.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_flow_topToBottom()
+{
+ QSGView *canvas = createView(SRCDIR "/data/flowtest-toptobottom.qml");
+
+ canvas->rootObject()->setProperty("testRightToLeft", false);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 50.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 50.0);
+ QCOMPARE(three->y(), 50.0);
+ QCOMPARE(four->x(), 100.0);
+ QCOMPARE(four->y(), 00.0);
+ QCOMPARE(five->x(), 100.0);
+ QCOMPARE(five->y(), 50.0);
+
+ QSGItem *flow = canvas->rootObject()->findChild<QSGItem*>("flow");
+ QVERIFY(flow);
+ QCOMPARE(flow->height(), 90.0);
+ QCOMPARE(flow->width(), 150.0);
+
+ canvas->rootObject()->setProperty("testRightToLeft", true);
+
+ QVERIFY(flow);
+ QCOMPARE(flow->height(), 90.0);
+ QCOMPARE(flow->width(), 150.0);
+
+ QCOMPARE(one->x(), 100.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 80.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 50.0);
+ QCOMPARE(three->y(), 50.0);
+ QCOMPARE(four->x(), 0.0);
+ QCOMPARE(four->y(), 0.0);
+ QCOMPARE(five->x(), 40.0);
+ QCOMPARE(five->y(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_flow_resize()
+{
+ QSGView *canvas = createView(SRCDIR "/data/flowtest.qml");
+
+ QSGItem *root = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(root);
+ root->setWidth(125);
+ root->setProperty("testRightToLeft", false);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+
+ QCOMPARE(one->x(), 0.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 50.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 70.0);
+ QCOMPARE(three->y(), 0.0);
+ QCOMPARE(four->x(), 0.0);
+ QCOMPARE(four->y(), 50.0);
+ QCOMPARE(five->x(), 50.0);
+ QCOMPARE(five->y(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_flow_resize_rightToLeft()
+{
+ QSGView *canvas = createView(SRCDIR "/data/flowtest.qml");
+
+ QSGItem *root = qobject_cast<QSGItem*>(canvas->rootObject());
+ QVERIFY(root);
+ root->setWidth(125);
+ root->setProperty("testRightToLeft", true);
+
+ QSGRectangle *one = canvas->rootObject()->findChild<QSGRectangle*>("one");
+ QVERIFY(one != 0);
+ QSGRectangle *two = canvas->rootObject()->findChild<QSGRectangle*>("two");
+ QVERIFY(two != 0);
+ QSGRectangle *three = canvas->rootObject()->findChild<QSGRectangle*>("three");
+ QVERIFY(three != 0);
+ QSGRectangle *four = canvas->rootObject()->findChild<QSGRectangle*>("four");
+ QVERIFY(four != 0);
+ QSGRectangle *five = canvas->rootObject()->findChild<QSGRectangle*>("five");
+ QVERIFY(five != 0);
+
+ QCOMPARE(one->x(), 75.0);
+ QCOMPARE(one->y(), 0.0);
+ QCOMPARE(two->x(), 55.0);
+ QCOMPARE(two->y(), 0.0);
+ QCOMPARE(three->x(), 5.0);
+ QCOMPARE(three->y(), 0.0);
+ QCOMPARE(four->x(), 75.0);
+ QCOMPARE(four->y(), 50.0);
+ QCOMPARE(five->x(), 65.0);
+ QCOMPARE(five->y(), 50.0);
+
+ delete canvas;
+}
+
+void tst_qsgpositioners::test_flow_implicit_resize()
+{
+ QSGView *canvas = createView(SRCDIR "/data/flow-testimplicitsize.qml");
+ QVERIFY(canvas->rootObject() != 0);
+
+ QSGFlow *flow = canvas->rootObject()->findChild<QSGFlow*>("flow");
+ QVERIFY(flow != 0);
+
+ QCOMPARE(flow->width(), 100.0);
+ QCOMPARE(flow->height(), 120.0);
+
+ canvas->rootObject()->setProperty("flowLayout", 0);
+ QCOMPARE(flow->flow(), QSGFlow::LeftToRight);
+ QCOMPARE(flow->width(), 220.0);
+ QCOMPARE(flow->height(), 50.0);
+
+ canvas->rootObject()->setProperty("flowLayout", 1);
+ QCOMPARE(flow->flow(), QSGFlow::TopToBottom);
+ QCOMPARE(flow->width(), 100.0);
+ QCOMPARE(flow->height(), 120.0);
+
+ canvas->rootObject()->setProperty("flowLayout", 2);
+ QCOMPARE(flow->layoutDirection(), Qt::RightToLeft);
+ QCOMPARE(flow->width(), 220.0);
+ QCOMPARE(flow->height(), 50.0);
+
+ delete canvas;
+}
+
+QString warningMessage;
+
+void interceptWarnings(QtMsgType type, const char *msg)
+{
+ Q_UNUSED( type );
+ warningMessage = msg;
+}
+
+void tst_qsgpositioners::test_conflictinganchors()
+{
+ QtMsgHandler oldMsgHandler = qInstallMsgHandler(interceptWarnings);
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine);
+
+ component.setData("import QtQuick 2.0\nColumn { Item {} }", QUrl::fromLocalFile(""));
+ QSGItem *item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QVERIFY(warningMessage.isEmpty());
+ delete item;
+
+ component.setData("import QtQuick 2.0\nRow { Item {} }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QVERIFY(warningMessage.isEmpty());
+ delete item;
+
+ component.setData("import QtQuick 2.0\nGrid { Item {} }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QVERIFY(warningMessage.isEmpty());
+ delete item;
+
+ component.setData("import QtQuick 2.0\nFlow { Item {} }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QVERIFY(warningMessage.isEmpty());
+ delete item;
+
+ component.setData("import QtQuick 2.0\nColumn { Item { anchors.top: parent.top } }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QCOMPARE(warningMessage, QString("file::2:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column"));
+ warningMessage.clear();
+ delete item;
+
+ component.setData("import QtQuick 2.0\nColumn { Item { anchors.centerIn: parent } }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QCOMPARE(warningMessage, QString("file::2:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column"));
+ warningMessage.clear();
+ delete item;
+
+ component.setData("import QtQuick 2.0\nColumn { Item { anchors.left: parent.left } }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QVERIFY(warningMessage.isEmpty());
+ warningMessage.clear();
+ delete item;
+
+ component.setData("import QtQuick 2.0\nRow { Item { anchors.left: parent.left } }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QCOMPARE(warningMessage, QString("file::2:1: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row"));
+ warningMessage.clear();
+ delete item;
+
+ component.setData("import QtQuick 2.0\nRow { Item { anchors.fill: parent } }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QCOMPARE(warningMessage, QString("file::2:1: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row"));
+ warningMessage.clear();
+ delete item;
+
+ component.setData("import QtQuick 2.0\nRow { Item { anchors.top: parent.top } }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QVERIFY(warningMessage.isEmpty());
+ warningMessage.clear();
+ delete item;
+
+ component.setData("import QtQuick 2.0\nGrid { Item { anchors.horizontalCenter: parent.horizontalCenter } }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QCOMPARE(warningMessage, QString("file::2:1: QML Grid: Cannot specify anchors for items inside Grid"));
+ warningMessage.clear();
+ delete item;
+
+ component.setData("import QtQuick 2.0\nGrid { Item { anchors.centerIn: parent } }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QCOMPARE(warningMessage, QString("file::2:1: QML Grid: Cannot specify anchors for items inside Grid"));
+ warningMessage.clear();
+ delete item;
+
+ component.setData("import QtQuick 2.0\nFlow { Item { anchors.verticalCenter: parent.verticalCenter } }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QCOMPARE(warningMessage, QString("file::2:1: QML Flow: Cannot specify anchors for items inside Flow"));
+ delete item;
+
+ component.setData("import QtQuick 2.0\nFlow { Item { anchors.fill: parent } }", QUrl::fromLocalFile(""));
+ item = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(item);
+ QCOMPARE(warningMessage, QString("file::2:1: QML Flow: Cannot specify anchors for items inside Flow"));
+ qInstallMsgHandler(oldMsgHandler);
+ delete item;
+}
+
+void tst_qsgpositioners::test_mirroring()
+{
+ QList<QString> qmlFiles;
+ qmlFiles << "horizontal.qml" << "gridtest.qml" << "flowtest.qml";
+ QList<QString> objectNames;
+ objectNames << "one" << "two" << "three" << "four" << "five";
+
+ foreach(const QString qmlFile, qmlFiles) {
+ QSGView *canvasA = createView(QString(SRCDIR) + "/data/" + qmlFile);
+ QSGItem *rootA = qobject_cast<QSGItem*>(canvasA->rootObject());
+
+ QSGView *canvasB = createView(QString(SRCDIR) + "/data/" + qmlFile);
+ QSGItem *rootB = qobject_cast<QSGItem*>(canvasB->rootObject());
+
+ rootA->setProperty("testRightToLeft", true); // layoutDirection: Qt.RightToLeft
+
+ // LTR != RTL
+ foreach(const QString objectName, objectNames) {
+ // horizontal.qml only has three items
+ if (qmlFile == QString("horizontal.qml") && objectName == QString("four"))
+ break;
+ QSGItem *itemA = rootA->findChild<QSGItem*>(objectName);
+ QSGItem *itemB = rootB->findChild<QSGItem*>(objectName);
+ QVERIFY(itemA->x() != itemB->x());
+ }
+
+ QSGItemPrivate* rootPrivateB = QSGItemPrivate::get(rootB);
+
+ rootPrivateB->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true
+ rootPrivateB->isMirrorImplicit = false;
+ rootPrivateB->inheritMirrorFromItem = true; // LayoutMirroring.childrenInherit: true
+ rootPrivateB->resolveLayoutMirror();
+
+ // RTL == mirror
+ foreach(const QString objectName, objectNames) {
+ // horizontal.qml only has three items
+ if (qmlFile == QString("horizontal.qml") && objectName == QString("four"))
+ break;
+ QSGItem *itemA = rootA->findChild<QSGItem*>(objectName);
+ QSGItem *itemB = rootB->findChild<QSGItem*>(objectName);
+ QCOMPARE(itemA->x(), itemB->x());
+ }
+
+ rootA->setProperty("testRightToLeft", false); // layoutDirection: Qt.LeftToRight
+ rootB->setProperty("testRightToLeft", true); // layoutDirection: Qt.RightToLeft
+
+ // LTR == RTL + mirror
+ foreach(const QString objectName, objectNames) {
+ // horizontal.qml only has three items
+ if (qmlFile == QString("horizontal.qml") && objectName == QString("four"))
+ break;
+ QSGItem *itemA = rootA->findChild<QSGItem*>(objectName);
+ QSGItem *itemB = rootB->findChild<QSGItem*>(objectName);
+ QCOMPARE(itemA->x(), itemB->x());
+ }
+ delete canvasA;
+ delete canvasB;
+ }
+}
+
+QSGView *tst_qsgpositioners::createView(const QString &filename)
+{
+ QSGView *canvas = new QSGView(0);
+
+ canvas->setSource(QUrl::fromLocalFile(filename));
+
+ return canvas;
+}
+
+
+QTEST_MAIN(tst_qsgpositioners)
+
+#include "tst_qsgpositioners.moc"
diff --git a/tests/auto/declarative/qsgrepeater/data/intmodel.qml b/tests/auto/declarative/qsgrepeater/data/intmodel.qml
new file mode 100644
index 0000000000..30a650dd52
--- /dev/null
+++ b/tests/auto/declarative/qsgrepeater/data/intmodel.qml
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: container
+ objectName: "container"
+ width: 240
+ height: 320
+ color: "white"
+
+ function checkProperties() {
+ testObject.error = false;
+ if (repeater.delegate != comp) {
+ console.log("delegate property incorrect");
+ testObject.error = true;
+ }
+ }
+
+ Component {
+ id: comp
+ Item{}
+ }
+
+ Repeater {
+ id: repeater
+ objectName: "repeater"
+ model: testData
+ delegate: comp
+ }
+}
diff --git a/tests/auto/declarative/qsgrepeater/data/itemlist.qml b/tests/auto/declarative/qsgrepeater/data/itemlist.qml
new file mode 100644
index 0000000000..174bfd4d18
--- /dev/null
+++ b/tests/auto/declarative/qsgrepeater/data/itemlist.qml
@@ -0,0 +1,68 @@
+// This example demonstrates placing items in a view using
+// a VisualItemModel
+
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ color: "lightgray"
+ width: 240
+ height: 320
+ property variant itemModel: itemModel1
+
+ function checkProperties() {
+ testObject.error = false;
+ if (testObject.useModel && view.model != root.itemModel) {
+ console.log("model property incorrect");
+ testObject.error = true;
+ }
+ }
+
+ function switchModel() {
+ root.itemModel = itemModel2
+ }
+
+ VisualItemModel {
+ id: itemModel1
+ objectName: "itemModel1"
+ Rectangle {
+ objectName: "item1"
+ height: 50; width: 100; color: "#FFFEF0"
+ Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ Rectangle {
+ objectName: "item2"
+ height: 50; width: 100; color: "#F0FFF7"
+ Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ Rectangle {
+ objectName: "item3"
+ height: 50; width: 100; color: "#F4F0FF"
+ Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ }
+
+ VisualItemModel {
+ id: itemModel2
+ objectName: "itemModel2"
+ Rectangle {
+ objectName: "item4"
+ height: 50; width: 100; color: "#FFFEF0"
+ Text { objectName: "text4"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ Rectangle {
+ objectName: "item5"
+ height: 50; width: 100; color: "#F0FFF7"
+ Text { objectName: "text5"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent }
+ }
+ }
+
+ Column {
+ objectName: "container"
+ Repeater {
+ id: view
+ objectName: "repeater"
+ model: testObject.useModel ? root.itemModel : 0
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgrepeater/data/modelChanged.qml b/tests/auto/declarative/qsgrepeater/data/modelChanged.qml
new file mode 100644
index 0000000000..23af127e79
--- /dev/null
+++ b/tests/auto/declarative/qsgrepeater/data/modelChanged.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+
+Column {
+ Repeater {
+ id: repeater
+ objectName: "repeater"
+
+ property int itemsCount
+ property variant itemsFound: []
+
+ delegate: Rectangle {
+ color: "red"
+ width: (index+1)*50
+ height: 50
+ }
+
+ onModelChanged: {
+ repeater.itemsCount = repeater.count
+ var items = []
+ for (var i=0; i<repeater.count; i++)
+ items.push(repeater.itemAt(i))
+ repeater.itemsFound = items
+ }
+ }
+}
+
diff --git a/tests/auto/declarative/qsgrepeater/data/objlist.qml b/tests/auto/declarative/qsgrepeater/data/objlist.qml
new file mode 100644
index 0000000000..c49d5926e5
--- /dev/null
+++ b/tests/auto/declarative/qsgrepeater/data/objlist.qml
@@ -0,0 +1,21 @@
+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{
+ Component.onCompleted: {if(index!=modelData.idx) repeater.errors += 1; repeater.instantiated++}
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgrepeater/data/properties.qml b/tests/auto/declarative/qsgrepeater/data/properties.qml
new file mode 100644
index 0000000000..035431c784
--- /dev/null
+++ b/tests/auto/declarative/qsgrepeater/data/properties.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+Row {
+ Repeater {
+ objectName: "repeater"
+ model: 5
+ Text {
+ text: "I'm item " + index
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgrepeater/data/repeater1.qml b/tests/auto/declarative/qsgrepeater/data/repeater1.qml
new file mode 100644
index 0000000000..596dc9131e
--- /dev/null
+++ b/tests/auto/declarative/qsgrepeater/data/repeater1.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: container
+ objectName: "container"
+ width: 240
+ height: 320
+ color: "white"
+ Text {
+ text: "Zero"
+ }
+ Repeater {
+ id: repeater
+ objectName: "repeater"
+ width: 240
+ height: 320
+ model: testData
+ Component {
+ Text {
+ y: index*20
+ text: modelData
+ }
+ }
+ }
+ Text {
+ text: "Last"
+ }
+}
diff --git a/tests/auto/declarative/qsgrepeater/data/repeater2.qml b/tests/auto/declarative/qsgrepeater/data/repeater2.qml
new file mode 100644
index 0000000000..691fbda1e5
--- /dev/null
+++ b/tests/auto/declarative/qsgrepeater/data/repeater2.qml
@@ -0,0 +1,36 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "white"
+ Component {
+ id: myDelegate
+ Item {
+ objectName: "myDelegate"
+ height: 20
+ width: 240
+ Text {
+ objectName: "myName"
+ text: name
+ }
+ Text {
+ objectName: "myNumber"
+ x: 100
+ text: number
+ }
+ }
+ }
+ Column {
+ id: container
+ objectName: "container"
+ Repeater {
+ id: repeater
+ objectName: "repeater"
+ width: 240
+ height: 320
+ delegate: myDelegate
+ model: testData
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgrepeater/qsgrepeater.pro b/tests/auto/declarative/qsgrepeater/qsgrepeater.pro
new file mode 100644
index 0000000000..99c3e1830b
--- /dev/null
+++ b/tests/auto/declarative/qsgrepeater/qsgrepeater.pro
@@ -0,0 +1,15 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qsgrepeater.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
diff --git a/tests/auto/declarative/qsgrepeater/tst_qsgrepeater.cpp b/tests/auto/declarative/qsgrepeater/tst_qsgrepeater.cpp
new file mode 100644
index 0000000000..e9d79629c6
--- /dev/null
+++ b/tests/auto/declarative/qsgrepeater/tst_qsgrepeater.cpp
@@ -0,0 +1,697 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtTest/QSignalSpy>
+#include <private/qlistmodelinterface_p.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qsgview.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <private/qsgrepeater_p.h>
+#include <private/qsgtext_p.h>
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+inline QUrl TEST_FILE(const QString &filename)
+{
+ return QUrl::fromLocalFile(QLatin1String(SRCDIR) + QLatin1String("/data/") + filename);
+}
+
+class tst_QSGRepeater : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QSGRepeater();
+
+private slots:
+ void numberModel();
+ void objectList();
+ void stringList();
+ void dataModel_adding();
+ void dataModel_removing();
+ void dataModel_changes();
+ void itemModel();
+ void resetModel();
+ void modelChanged();
+ void properties();
+
+private:
+ QSGView *createView();
+ template<typename T>
+ T *findItem(QObject *parent, const QString &objectName, int index);
+ template<typename T>
+ T *findItem(QObject *parent, const QString &id);
+};
+
+class TestObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool error READ error WRITE setError)
+ Q_PROPERTY(bool useModel READ useModel NOTIFY useModelChanged)
+
+public:
+ TestObject() : QObject(), mError(true), mUseModel(false) {}
+
+ bool error() const { return mError; }
+ void setError(bool err) { mError = err; }
+
+ bool useModel() const { return mUseModel; }
+ void setUseModel(bool use) { mUseModel = use; emit useModelChanged(); }
+
+signals:
+ void useModelChanged();
+
+private:
+ bool mError;
+ bool mUseModel;
+};
+
+class TestModel : public QAbstractListModel
+{
+public:
+ enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
+
+ TestModel(QObject *parent=0) : QAbstractListModel(parent) {
+ QHash<int, QByteArray> roles;
+ roles[Name] = "name";
+ roles[Number] = "number";
+ setRoleNames(roles);
+ }
+
+ int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
+ QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
+ QVariant rv;
+ if (role == Name)
+ rv = list.at(index.row()).first;
+ else if (role == Number)
+ rv = list.at(index.row()).second;
+
+ return rv;
+ }
+
+ int count() const { return rowCount(); }
+ QString name(int index) const { return list.at(index).first; }
+ QString number(int index) const { return list.at(index).second; }
+
+ void addItem(const QString &name, const QString &number) {
+ emit beginInsertRows(QModelIndex(), list.count(), list.count());
+ list.append(QPair<QString,QString>(name, number));
+ emit endInsertRows();
+ }
+
+ void insertItem(int index, const QString &name, const QString &number) {
+ emit beginInsertRows(QModelIndex(), index, index);
+ list.insert(index, QPair<QString,QString>(name, number));
+ emit endInsertRows();
+ }
+
+ void removeItem(int index) {
+ emit beginRemoveRows(QModelIndex(), index, index);
+ list.removeAt(index);
+ emit endRemoveRows();
+ }
+
+ void moveItem(int from, int to) {
+ emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
+ list.move(from, to);
+ emit endMoveRows();
+ }
+
+ void modifyItem(int idx, const QString &name, const QString &number) {
+ list[idx] = QPair<QString,QString>(name, number);
+ emit dataChanged(index(idx,0), index(idx,0));
+ }
+
+private:
+ QList<QPair<QString,QString> > list;
+};
+
+
+tst_QSGRepeater::tst_QSGRepeater()
+{
+}
+
+void tst_QSGRepeater::numberModel()
+{
+ QSGView *canvas = createView();
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testData", 5);
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/intmodel.qml"));
+ qApp->processEvents();
+
+ QSGRepeater *repeater = findItem<QSGRepeater>(canvas->rootObject(), "repeater");
+ QVERIFY(repeater != 0);
+ QCOMPARE(repeater->parentItem()->childItems().count(), 5+1);
+
+ QVERIFY(!repeater->itemAt(-1));
+ for (int i=0; i<repeater->count(); i++)
+ QCOMPARE(repeater->itemAt(i), repeater->parentItem()->childItems().at(i));
+ QVERIFY(!repeater->itemAt(repeater->count()));
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
+ QVERIFY(testObject->error() == false);
+
+ delete testObject;
+ delete canvas;
+}
+
+class MyObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int idx READ idx CONSTANT)
+public:
+ MyObject(int i) : QObject(), m_idx(i) {}
+
+ int idx() const { return m_idx; }
+
+ int m_idx;
+};
+
+void tst_QSGRepeater::objectList()
+{
+ QSGView *canvas = createView();
+ QObjectList data;
+ for(int i=0; i<100; i++)
+ data << new MyObject(i);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testData", QVariant::fromValue(data));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/objlist.qml"));
+ qApp->processEvents();
+
+ QSGRepeater *repeater = findItem<QSGRepeater>(canvas->rootObject(), "repeater");
+ QVERIFY(repeater != 0);
+ QCOMPARE(repeater->property("errors").toInt(), 0);//If this fails either they are out of order or can't find the object's data
+ QCOMPARE(repeater->property("instantiated").toInt(), 100);
+
+ QVERIFY(!repeater->itemAt(-1));
+ for (int i=0; i<data.count(); i++)
+ QCOMPARE(repeater->itemAt(i), repeater->parentItem()->childItems().at(i));
+ QVERIFY(!repeater->itemAt(data.count()));
+
+ QSignalSpy addedSpy(repeater, SIGNAL(itemAdded(int,QSGItem*)));
+ QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QSGItem*)));
+ ctxt->setContextProperty("testData", QVariant::fromValue(data));
+ QCOMPARE(addedSpy.count(), data.count());
+ QCOMPARE(removedSpy.count(), data.count());
+
+ qDeleteAll(data);
+ delete canvas;
+}
+
+/*
+The Repeater element creates children at its own position in its parent's
+stacking order. In this test we insert a repeater between two other Text
+elements to test this.
+*/
+void tst_QSGRepeater::stringList()
+{
+ QSGView *canvas = createView();
+
+ QStringList data;
+ data << "One";
+ data << "Two";
+ data << "Three";
+ data << "Four";
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testData", data);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/repeater1.qml"));
+ qApp->processEvents();
+
+ QSGRepeater *repeater = findItem<QSGRepeater>(canvas->rootObject(), "repeater");
+ QVERIFY(repeater != 0);
+
+ QSGItem *container = findItem<QSGItem>(canvas->rootObject(), "container");
+ QVERIFY(container != 0);
+
+ QCOMPARE(container->childItems().count(), data.count() + 3);
+
+ bool saw_repeater = false;
+ for (int i = 0; i < container->childItems().count(); ++i) {
+
+ if (i == 0) {
+ QSGText *name = qobject_cast<QSGText*>(container->childItems().at(i));
+ QVERIFY(name != 0);
+ QCOMPARE(name->text(), QLatin1String("Zero"));
+ } else if (i == container->childItems().count() - 2) {
+ // The repeater itself
+ QSGRepeater *rep = qobject_cast<QSGRepeater*>(container->childItems().at(i));
+ QCOMPARE(rep, repeater);
+ saw_repeater = true;
+ continue;
+ } else if (i == container->childItems().count() - 1) {
+ QSGText *name = qobject_cast<QSGText*>(container->childItems().at(i));
+ QVERIFY(name != 0);
+ QCOMPARE(name->text(), QLatin1String("Last"));
+ } else {
+ QSGText *name = qobject_cast<QSGText*>(container->childItems().at(i));
+ QVERIFY(name != 0);
+ QCOMPARE(name->text(), data.at(i-1));
+ }
+ }
+ QVERIFY(saw_repeater);
+
+ delete canvas;
+}
+
+void tst_QSGRepeater::dataModel_adding()
+{
+ QSGView *canvas = createView();
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ TestModel testModel;
+ ctxt->setContextProperty("testData", &testModel);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/repeater2.qml"));
+ qApp->processEvents();
+
+ QSGRepeater *repeater = findItem<QSGRepeater>(canvas->rootObject(), "repeater");
+ QVERIFY(repeater != 0);
+ QSGItem *container = findItem<QSGItem>(canvas->rootObject(), "container");
+ QVERIFY(container != 0);
+
+ QVERIFY(!repeater->itemAt(0));
+
+ QSignalSpy countSpy(repeater, SIGNAL(countChanged()));
+ QSignalSpy addedSpy(repeater, SIGNAL(itemAdded(int,QSGItem*)));
+
+ // add to empty model
+ testModel.addItem("two", "2");
+ QCOMPARE(repeater->itemAt(0), container->childItems().at(0));
+ QCOMPARE(countSpy.count(), 1); countSpy.clear();
+ QCOMPARE(addedSpy.count(), 1);
+ QCOMPARE(addedSpy.at(0).at(0).toInt(), 0);
+ QCOMPARE(addedSpy.at(0).at(1).value<QSGItem*>(), container->childItems().at(0));
+ addedSpy.clear();
+
+ // insert at start
+ testModel.insertItem(0, "one", "1");
+ QCOMPARE(repeater->itemAt(0), container->childItems().at(0));
+ QCOMPARE(countSpy.count(), 1); countSpy.clear();
+ QCOMPARE(addedSpy.count(), 1);
+ QCOMPARE(addedSpy.at(0).at(0).toInt(), 0);
+ QCOMPARE(addedSpy.at(0).at(1).value<QSGItem*>(), container->childItems().at(0));
+ addedSpy.clear();
+
+ // insert at end
+ testModel.insertItem(2, "four", "4");
+ QCOMPARE(repeater->itemAt(2), container->childItems().at(2));
+ QCOMPARE(countSpy.count(), 1); countSpy.clear();
+ QCOMPARE(addedSpy.count(), 1);
+ QCOMPARE(addedSpy.at(0).at(0).toInt(), 2);
+ QCOMPARE(addedSpy.at(0).at(1).value<QSGItem*>(), container->childItems().at(2));
+ addedSpy.clear();
+
+ // insert in middle
+ testModel.insertItem(2, "three", "3");
+ QCOMPARE(repeater->itemAt(2), container->childItems().at(2));
+ QCOMPARE(countSpy.count(), 1); countSpy.clear();
+ QCOMPARE(addedSpy.count(), 1);
+ QCOMPARE(addedSpy.at(0).at(0).toInt(), 2);
+ QCOMPARE(addedSpy.at(0).at(1).value<QSGItem*>(), container->childItems().at(2));
+ addedSpy.clear();
+
+ delete testObject;
+ addedSpy.clear();
+ countSpy.clear();
+ delete canvas;
+}
+
+void tst_QSGRepeater::dataModel_removing()
+{
+ QSGView *canvas = createView();
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ TestModel testModel;
+ testModel.addItem("one", "1");
+ testModel.addItem("two", "2");
+ testModel.addItem("three", "3");
+ testModel.addItem("four", "4");
+ testModel.addItem("five", "5");
+
+ ctxt->setContextProperty("testData", &testModel);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/repeater2.qml"));
+ qApp->processEvents();
+
+ QSGRepeater *repeater = findItem<QSGRepeater>(canvas->rootObject(), "repeater");
+ QVERIFY(repeater != 0);
+ QSGItem *container = findItem<QSGItem>(canvas->rootObject(), "container");
+ QVERIFY(container != 0);
+ QCOMPARE(container->childItems().count(), repeater->count()+1);
+
+ QSignalSpy countSpy(repeater, SIGNAL(countChanged()));
+ QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QSGItem*)));
+
+ // remove at start
+ QSGItem *item = repeater->itemAt(0);
+ QCOMPARE(item, container->childItems().at(0));
+
+ testModel.removeItem(0);
+ QVERIFY(repeater->itemAt(0) != item);
+ QCOMPARE(countSpy.count(), 1); countSpy.clear();
+ QCOMPARE(removedSpy.count(), 1);
+ QCOMPARE(removedSpy.at(0).at(0).toInt(), 0);
+ QCOMPARE(removedSpy.at(0).at(1).value<QSGItem*>(), item);
+ removedSpy.clear();
+
+ // remove at end
+ int lastIndex = testModel.count()-1;
+ item = repeater->itemAt(lastIndex);
+ QCOMPARE(item, container->childItems().at(lastIndex));
+
+ testModel.removeItem(lastIndex);
+ QVERIFY(repeater->itemAt(lastIndex) != item);
+ QCOMPARE(countSpy.count(), 1); countSpy.clear();
+ QCOMPARE(removedSpy.count(), 1);
+ QCOMPARE(removedSpy.at(0).at(0).toInt(), lastIndex);
+ QCOMPARE(removedSpy.at(0).at(1).value<QSGItem*>(), item);
+ removedSpy.clear();
+
+ // remove from middle
+ item = repeater->itemAt(1);
+ QCOMPARE(item, container->childItems().at(1));
+
+ testModel.removeItem(1);
+ QVERIFY(repeater->itemAt(lastIndex) != item);
+ QCOMPARE(countSpy.count(), 1); countSpy.clear();
+ QCOMPARE(removedSpy.count(), 1);
+ QCOMPARE(removedSpy.at(0).at(0).toInt(), 1);
+ QCOMPARE(removedSpy.at(0).at(1).value<QSGItem*>(), item);
+ removedSpy.clear();
+
+ delete testObject;
+ delete canvas;
+}
+
+void tst_QSGRepeater::dataModel_changes()
+{
+ QSGView *canvas = createView();
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ TestModel testModel;
+ testModel.addItem("one", "1");
+ testModel.addItem("two", "2");
+ testModel.addItem("three", "3");
+
+ ctxt->setContextProperty("testData", &testModel);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/repeater2.qml"));
+ qApp->processEvents();
+
+ QSGRepeater *repeater = findItem<QSGRepeater>(canvas->rootObject(), "repeater");
+ QVERIFY(repeater != 0);
+ QSGItem *container = findItem<QSGItem>(canvas->rootObject(), "container");
+ QVERIFY(container != 0);
+ QCOMPARE(container->childItems().count(), repeater->count()+1);
+
+ // Check that model changes are propagated
+ QSGText *text = findItem<QSGText>(canvas->rootObject(), "myName", 1);
+ QVERIFY(text);
+ QCOMPARE(text->text(), QString("two"));
+
+ testModel.modifyItem(1, "Item two", "_2");
+ text = findItem<QSGText>(canvas->rootObject(), "myName", 1);
+ QVERIFY(text);
+ QCOMPARE(text->text(), QString("Item two"));
+
+ text = findItem<QSGText>(canvas->rootObject(), "myNumber", 1);
+ QVERIFY(text);
+ QCOMPARE(text->text(), QString("_2"));
+
+ delete testObject;
+ delete canvas;
+}
+
+void tst_QSGRepeater::itemModel()
+{
+ QSGView *canvas = createView();
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/itemlist.qml"));
+ qApp->processEvents();
+
+ QSGRepeater *repeater = findItem<QSGRepeater>(canvas->rootObject(), "repeater");
+ QVERIFY(repeater != 0);
+
+ QSGItem *container = findItem<QSGItem>(canvas->rootObject(), "container");
+ QVERIFY(container != 0);
+
+ QCOMPARE(container->childItems().count(), 1);
+
+ testObject->setUseModel(true);
+ QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
+ QVERIFY(testObject->error() == false);
+
+ QCOMPARE(container->childItems().count(), 4);
+ QVERIFY(qobject_cast<QObject*>(container->childItems().at(0))->objectName() == "item1");
+ QVERIFY(qobject_cast<QObject*>(container->childItems().at(1))->objectName() == "item2");
+ QVERIFY(qobject_cast<QObject*>(container->childItems().at(2))->objectName() == "item3");
+ QVERIFY(container->childItems().at(3) == repeater);
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "switchModel");
+ QCOMPARE(container->childItems().count(), 3);
+ QVERIFY(qobject_cast<QObject*>(container->childItems().at(0))->objectName() == "item4");
+ QVERIFY(qobject_cast<QObject*>(container->childItems().at(1))->objectName() == "item5");
+ QVERIFY(container->childItems().at(2) == repeater);
+
+ testObject->setUseModel(false);
+ QCOMPARE(container->childItems().count(), 1);
+
+ delete testObject;
+ delete canvas;
+}
+
+void tst_QSGRepeater::resetModel()
+{
+ QSGView *canvas = createView();
+
+ QStringList dataA;
+ for (int i=0; i<10; i++)
+ dataA << QString::number(i);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testData", dataA);
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/repeater1.qml"));
+ qApp->processEvents();
+ QSGRepeater *repeater = findItem<QSGRepeater>(canvas->rootObject(), "repeater");
+ QVERIFY(repeater != 0);
+ QSGItem *container = findItem<QSGItem>(canvas->rootObject(), "container");
+ QVERIFY(container != 0);
+
+ QCOMPARE(repeater->count(), dataA.count());
+ for (int i=0; i<repeater->count(); i++)
+ QCOMPARE(repeater->itemAt(i), container->childItems().at(i+1)); // +1 to skip first Text object
+
+ QSignalSpy modelChangedSpy(repeater, SIGNAL(modelChanged()));
+ QSignalSpy countSpy(repeater, SIGNAL(countChanged()));
+ QSignalSpy addedSpy(repeater, SIGNAL(itemAdded(int,QSGItem*)));
+ QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QSGItem*)));
+
+ QStringList dataB;
+ for (int i=0; i<20; i++)
+ dataB << QString::number(i);
+
+ // reset context property
+ ctxt->setContextProperty("testData", dataB);
+ QCOMPARE(repeater->count(), dataB.count());
+
+ QCOMPARE(modelChangedSpy.count(), 1);
+ QCOMPARE(countSpy.count(), 1);
+ QCOMPARE(removedSpy.count(), dataA.count());
+ QCOMPARE(addedSpy.count(), dataB.count());
+ for (int i=0; i<dataB.count(); i++) {
+ QCOMPARE(addedSpy.at(i).at(0).toInt(), i);
+ QCOMPARE(addedSpy.at(i).at(1).value<QSGItem*>(), repeater->itemAt(i));
+ }
+ modelChangedSpy.clear();
+ countSpy.clear();
+ removedSpy.clear();
+ addedSpy.clear();
+
+ // reset via setModel()
+ repeater->setModel(dataA);
+ QCOMPARE(repeater->count(), dataA.count());
+
+ QCOMPARE(modelChangedSpy.count(), 1);
+ QCOMPARE(countSpy.count(), 1);
+ QCOMPARE(removedSpy.count(), dataB.count());
+ QCOMPARE(addedSpy.count(), dataA.count());
+ for (int i=0; i<dataA.count(); i++) {
+ QCOMPARE(addedSpy.at(i).at(0).toInt(), i);
+ QCOMPARE(addedSpy.at(i).at(1).value<QSGItem*>(), repeater->itemAt(i));
+ }
+
+ modelChangedSpy.clear();
+ countSpy.clear();
+ removedSpy.clear();
+ addedSpy.clear();
+
+ delete canvas;
+}
+
+// QTBUG-17156
+void tst_QSGRepeater::modelChanged()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, TEST_FILE("/modelChanged.qml"));
+
+ QSGItem *rootObject = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(rootObject);
+ QSGRepeater *repeater = findItem<QSGRepeater>(rootObject, "repeater");
+ QVERIFY(repeater);
+
+ repeater->setModel(4);
+ QCOMPARE(repeater->count(), 4);
+ QCOMPARE(repeater->property("itemsCount").toInt(), 4);
+ QCOMPARE(repeater->property("itemsFound").toList().count(), 4);
+
+ repeater->setModel(10);
+ QCOMPARE(repeater->count(), 10);
+ QCOMPARE(repeater->property("itemsCount").toInt(), 10);
+ QCOMPARE(repeater->property("itemsFound").toList().count(), 10);
+
+ delete rootObject;
+}
+
+void tst_QSGRepeater::properties()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, TEST_FILE("/properties.qml"));
+
+ QSGItem *rootObject = qobject_cast<QSGItem*>(component.create());
+ QVERIFY(rootObject);
+
+ QSGRepeater *repeater = findItem<QSGRepeater>(rootObject, "repeater");
+ QVERIFY(repeater);
+
+ QSignalSpy modelSpy(repeater, SIGNAL(modelChanged()));
+ repeater->setModel(3);
+ QCOMPARE(modelSpy.count(),1);
+ repeater->setModel(3);
+ QCOMPARE(modelSpy.count(),1);
+
+ QSignalSpy delegateSpy(repeater, SIGNAL(delegateChanged()));
+
+ QDeclarativeComponent rectComponent(&engine);
+ rectComponent.setData("import QtQuick 2.0; Rectangle {}", QUrl::fromLocalFile(""));
+
+ repeater->setDelegate(&rectComponent);
+ QCOMPARE(delegateSpy.count(),1);
+ repeater->setDelegate(&rectComponent);
+ QCOMPARE(delegateSpy.count(),1);
+
+ delete rootObject;
+}
+
+QSGView *tst_QSGRepeater::createView()
+{
+ QSGView *canvas = new QSGView(0);
+ canvas->setFixedSize(240,320);
+
+ return canvas;
+}
+
+template<typename T>
+T *tst_QSGRepeater::findItem(QObject *parent, const QString &objectName, int index)
+{
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->children().count() << "children";
+ for (int i = 0; i < parent->children().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->children().at(i));
+ if(!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ if (index != -1) {
+ QDeclarativeExpression e(qmlContext(item), item, "index");
+ if (e.evaluate().toInt() == index)
+ return static_cast<T*>(item);
+ } else {
+ return static_cast<T*>(item);
+ }
+ }
+ item = findItem<T>(item, objectName, index);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+}
+
+template<typename T>
+T *tst_QSGRepeater::findItem(QObject *parent, const QString &objectName)
+{
+ const QMetaObject &mo = T::staticMetaObject;
+ if (mo.cast(parent) && (objectName.isEmpty() || parent->objectName() == objectName))
+ return static_cast<T*>(parent);
+ for (int i = 0; i < parent->children().count(); ++i) {
+ QSGItem *child = qobject_cast<QSGItem*>(parent->children().at(i));
+ if (!child)
+ continue;
+ QSGItem *item = findItem<T>(child, objectName);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+}
+
+QTEST_MAIN(tst_QSGRepeater)
+
+#include "tst_qsgrepeater.moc"
diff --git a/tests/auto/declarative/qsgtext/data/alignments.qml b/tests/auto/declarative/qsgtext/data/alignments.qml
new file mode 100644
index 0000000000..9798d9c736
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/alignments.qml
@@ -0,0 +1,41 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: top
+ width: 70; height: 70;
+
+ property alias horizontalAlignment: t.horizontalAlignment
+ property alias verticalAlignment: t.verticalAlignment
+ property alias wrapMode: t.wrapMode
+ property alias running: timer.running
+ property string txt: "Test"
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 40
+ height: 40
+ color: "green"
+
+ Text {
+ id: t
+
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignBottom
+ wrapMode: Text.WordWrap
+ text: top.txt
+ }
+ Timer {
+ id: timer
+
+ interval: 1
+ running: true
+ repeat: true
+ onTriggered: {
+ top.txt = top.txt + "<br>more " + top.txt.length;
+ if (top.txt.length > 50)
+ running = false
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgtext/data/alignments_cb.png b/tests/auto/declarative/qsgtext/data/alignments_cb.png
new file mode 100644
index 0000000000..cf6199a418
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/alignments_cb.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtext/data/alignments_cc.png b/tests/auto/declarative/qsgtext/data/alignments_cc.png
new file mode 100644
index 0000000000..f81ccb4238
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/alignments_cc.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtext/data/alignments_ct.png b/tests/auto/declarative/qsgtext/data/alignments_ct.png
new file mode 100644
index 0000000000..9ba64125d5
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/alignments_ct.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtext/data/alignments_lb.png b/tests/auto/declarative/qsgtext/data/alignments_lb.png
new file mode 100644
index 0000000000..1b50a81f3d
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/alignments_lb.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtext/data/alignments_lc.png b/tests/auto/declarative/qsgtext/data/alignments_lc.png
new file mode 100644
index 0000000000..f041b868f8
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/alignments_lc.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtext/data/alignments_lt.png b/tests/auto/declarative/qsgtext/data/alignments_lt.png
new file mode 100644
index 0000000000..c75e0d158e
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/alignments_lt.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtext/data/alignments_rb.png b/tests/auto/declarative/qsgtext/data/alignments_rb.png
new file mode 100644
index 0000000000..b06a5da715
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/alignments_rb.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtext/data/alignments_rc.png b/tests/auto/declarative/qsgtext/data/alignments_rc.png
new file mode 100644
index 0000000000..e468857cd0
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/alignments_rc.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtext/data/alignments_rt.png b/tests/auto/declarative/qsgtext/data/alignments_rt.png
new file mode 100644
index 0000000000..576715ffce
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/alignments_rt.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtext/data/embeddedImagesLocal.qml b/tests/auto/declarative/qsgtext/data/embeddedImagesLocal.qml
new file mode 100644
index 0000000000..d71e9bb5bf
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/embeddedImagesLocal.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Text {
+ text: "<img src='http/exists.png'>"
+}
diff --git a/tests/auto/declarative/qsgtext/data/embeddedImagesLocalError.qml b/tests/auto/declarative/qsgtext/data/embeddedImagesLocalError.qml
new file mode 100644
index 0000000000..e6719481db
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/embeddedImagesLocalError.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Text {
+ text: "<img src='http/notexists.png'>"
+}
diff --git a/tests/auto/declarative/qsgtext/data/embeddedImagesRemote.qml b/tests/auto/declarative/qsgtext/data/embeddedImagesRemote.qml
new file mode 100644
index 0000000000..e524d028b5
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/embeddedImagesRemote.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Text {
+ text: "<img src='http://127.0.0.1:14453/exists.png'>"
+}
diff --git a/tests/auto/declarative/qsgtext/data/embeddedImagesRemoteError.qml b/tests/auto/declarative/qsgtext/data/embeddedImagesRemoteError.qml
new file mode 100644
index 0000000000..f541e0e497
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/embeddedImagesRemoteError.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Text {
+ text: "<img src='http://127.0.0.1:14453/notexists.png'>"
+}
diff --git a/tests/auto/declarative/qsgtext/data/horizontalAlignment_RightToLeft.qml b/tests/auto/declarative/qsgtext/data/horizontalAlignment_RightToLeft.qml
new file mode 100644
index 0000000000..5ba4d35684
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/horizontalAlignment_RightToLeft.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: top
+ width: 200; height: 70;
+
+ property alias horizontalAlignment: text.horizontalAlignment
+ property string text: "اختبا"
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 180
+ height: 20
+ color: "green"
+
+ Text {
+ id: text
+ objectName: "text"
+ anchors.fill: parent
+ text: top.text
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgtext/data/http/exists.png b/tests/auto/declarative/qsgtext/data/http/exists.png
new file mode 100644
index 0000000000..399bd0b1d9
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/http/exists.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtext/data/lineCount.qml b/tests/auto/declarative/qsgtext/data/lineCount.qml
new file mode 100644
index 0000000000..b672863684
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/lineCount.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+
+Item {
+ width: 200
+ height: 200
+
+ Text {
+ id: myText
+ objectName: "myText"
+ width: 200
+ wrapMode: Text.WordWrap
+ maximumLineCount: undefined
+ text: "Testing that maximumLines, visibleLines, and totalLines works properly in the autotests. The quick brown fox jumped over the lazy anything with the letter 'g'."
+ }
+}
diff --git a/tests/auto/declarative/qsgtext/data/lineHeight.qml b/tests/auto/declarative/qsgtext/data/lineHeight.qml
new file mode 100644
index 0000000000..c1f337aa05
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/lineHeight.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+
+Item {
+ width: 200
+ height: 200
+
+ Text {
+ id: myText
+ objectName: "myText"
+ width: 200
+ wrapMode: Text.WordWrap
+ font.pixelSize: 13
+ text: "Lorem ipsum sit amet, consectetur adipiscing elit. Integer felis nisl, varius in pretium nec, venenatis non erat. Proin lobortis interdum dictum."
+ }
+}
diff --git a/tests/auto/declarative/qsgtext/data/qtbug_14734.qml b/tests/auto/declarative/qsgtext/data/qtbug_14734.qml
new file mode 100644
index 0000000000..e71a798421
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/qtbug_14734.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 640
+ height: 480
+
+ Text {
+ text: "í "
+ }
+}
diff --git a/tests/auto/declarative/qsgtext/data/rotated.qml b/tests/auto/declarative/qsgtext/data/rotated.qml
new file mode 100644
index 0000000000..fecf64b249
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/data/rotated.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Rectangle {
+ width : 200
+ height : 100
+
+ Text {
+ objectName: "text"
+ x: 20
+ y: 20
+ height : 20
+ width : 80
+ text : "Something"
+ rotation : 30
+ transformOrigin : Item.TopLeft
+ }
+}
+
diff --git a/tests/auto/declarative/qsgtext/qsgtext.pro b/tests/auto/declarative/qsgtext/qsgtext.pro
new file mode 100644
index 0000000000..132cec4cdc
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/qsgtext.pro
@@ -0,0 +1,21 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui
+QT += network
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qsgtext.cpp
+
+INCLUDEPATH += ../shared/
+HEADERS += ../shared/testhttpserver.h
+SOURCES += ../shared/testhttpserver.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgtext/tst_qsgtext.cpp b/tests/auto/declarative/qsgtext/tst_qsgtext.cpp
new file mode 100644
index 0000000000..51184885db
--- /dev/null
+++ b/tests/auto/declarative/qsgtext/tst_qsgtext.cpp
@@ -0,0 +1,1432 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QTextDocument>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <private/qsgtext_p.h>
+#include <private/qsgtext_p_p.h>
+#include <private/qdeclarativevaluetype_p.h>
+#include <QFontMetrics>
+#include <QGraphicsSceneMouseEvent>
+#include <qmath.h>
+#include <QSGView>
+#include <private/qapplication_p.h>
+#include <limits.h>
+
+#include "../../../shared/util.h"
+#include "testhttpserver.h"
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+class tst_qsgtext : public QObject
+
+{
+ Q_OBJECT
+public:
+ tst_qsgtext();
+
+private slots:
+ void text();
+ void width();
+ void wrap();
+ void elide();
+ void textFormat();
+
+ void alignments_data();
+ void alignments();
+
+ void embeddedImages_data();
+ void embeddedImages();
+
+ void lineCount();
+ void lineHeight();
+
+ // ### these tests may be trivial
+ void horizontalAlignment();
+ void horizontalAlignment_RightToLeft();
+ void verticalAlignment();
+ void font();
+ void style();
+ void color();
+ void smooth();
+
+ // QDeclarativeFontValueType
+ void weight();
+ void underline();
+ void overline();
+ void strikeout();
+ void capitalization();
+ void letterSpacing();
+ void wordSpacing();
+
+ void clickLink();
+
+ void QTBUG_12291();
+ void implicitSize_data();
+ void implicitSize();
+ void testQtQuick11Attributes();
+ void testQtQuick11Attributes_data();
+
+ void qtbug_14734();
+private:
+ QStringList standard;
+ QStringList richText;
+
+ QStringList horizontalAlignmentmentStrings;
+ QStringList verticalAlignmentmentStrings;
+
+ QList<Qt::Alignment> verticalAlignmentments;
+ QList<Qt::Alignment> horizontalAlignmentments;
+
+ QStringList styleStrings;
+ QList<QSGText::TextStyle> styles;
+
+ QStringList colorStrings;
+
+ QDeclarativeEngine engine;
+
+ QSGView *createView(const QString &filename);
+};
+
+tst_qsgtext::tst_qsgtext()
+{
+ standard << "the quick brown fox jumped over the lazy dog"
+ << "the quick brown fox\n jumped over the lazy dog";
+
+ richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
+ << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
+
+ horizontalAlignmentmentStrings << "AlignLeft"
+ << "AlignRight"
+ << "AlignHCenter";
+
+ verticalAlignmentmentStrings << "AlignTop"
+ << "AlignBottom"
+ << "AlignVCenter";
+
+ horizontalAlignmentments << Qt::AlignLeft
+ << Qt::AlignRight
+ << Qt::AlignHCenter;
+
+ verticalAlignmentments << Qt::AlignTop
+ << Qt::AlignBottom
+ << Qt::AlignVCenter;
+
+ styleStrings << "Normal"
+ << "Outline"
+ << "Raised"
+ << "Sunken";
+
+ styles << QSGText::Normal
+ << QSGText::Outline
+ << QSGText::Raised
+ << QSGText::Sunken;
+
+ colorStrings << "aliceblue"
+ << "antiquewhite"
+ << "aqua"
+ << "darkkhaki"
+ << "darkolivegreen"
+ << "dimgray"
+ << "palevioletred"
+ << "lightsteelblue"
+ << "#000000"
+ << "#AAAAAA"
+ << "#FFFFFF"
+ << "#2AC05F";
+ //
+ // need a different test to do alpha channel test
+ // << "#AA0011DD"
+ // << "#00F16B11";
+ //
+}
+
+QSGView *tst_qsgtext::createView(const QString &filename)
+{
+ QSGView *canvas = new QSGView(0);
+
+ canvas->setSource(QUrl::fromLocalFile(filename));
+ return canvas;
+}
+
+void tst_qsgtext::text()
+{
+ {
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->text(), QString(""));
+ QVERIFY(textObject->width() == 0);
+
+ delete textObject;
+ }
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->text(), standard.at(i));
+ QVERIFY(textObject->width() > 0);
+
+ delete textObject;
+ }
+
+ for (int i = 0; i < richText.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QString expected = richText.at(i);
+ QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
+ QVERIFY(textObject->width() > 0);
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::width()
+{
+ // uses Font metrics to find the width for standard and document to find the width for rich
+ {
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->width(), 0.);
+
+ delete textObject;
+ }
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ QVERIFY(!Qt::mightBeRichText(standard.at(i))); // self-test
+
+ QFont f;
+ QFontMetricsF fm(f);
+ qreal metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
+ metricWidth = qCeil(metricWidth);
+
+ QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QVERIFY(textObject->boundingRect().width() > 0);
+ QCOMPARE(textObject->width(), qreal(metricWidth));
+ QVERIFY(textObject->textFormat() == QSGText::AutoText); // setting text doesn't change format
+
+ delete textObject;
+ }
+
+ for (int i = 0; i < richText.size(); i++)
+ {
+ QVERIFY(Qt::mightBeRichText(richText.at(i))); // self-test
+
+ QTextDocument document;
+ document.setHtml(richText.at(i));
+ document.setDocumentMargin(0);
+
+ int documentWidth = document.idealWidth();
+
+ QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->width(), qreal(documentWidth));
+ QVERIFY(textObject->textFormat() == QSGText::AutoText); // setting text doesn't change format
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::wrap()
+{
+ int textHeight = 0;
+ // for specified width and wrap set true
+ {
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+ textHeight = textObject->height();
+
+ QVERIFY(textObject != 0);
+ QVERIFY(textObject->wrapMode() == QSGText::WordWrap);
+ QCOMPARE(textObject->width(), 300.);
+
+ delete textObject;
+ }
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->width(), 30.);
+ QVERIFY(textObject->height() > textHeight);
+
+ int oldHeight = textObject->height();
+ textObject->setWidth(100);
+ QVERIFY(textObject->height() < oldHeight);
+
+ delete textObject;
+ }
+
+ for (int i = 0; i < richText.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->width(), 30.);
+ QVERIFY(textObject->height() > textHeight);
+
+ qreal oldHeight = textObject->height();
+ textObject->setWidth(100);
+ QVERIFY(textObject->height() < oldHeight);
+
+ delete textObject;
+ }
+
+ // richtext again with a fixed height
+ for (int i = 0; i < richText.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->width(), 30.);
+ QVERIFY(textObject->implicitHeight() > textHeight);
+
+ qreal oldHeight = textObject->implicitHeight();
+ textObject->setWidth(100);
+ QVERIFY(textObject->implicitHeight() < oldHeight);
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::elide()
+{
+ for (QSGText::TextElideMode m = QSGText::ElideLeft; m<=QSGText::ElideNone; m=QSGText::TextElideMode(int(m)+1)) {
+ const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"};
+ QString elide = "elide: Text." + QString(elidename[int(m)]) + ";";
+
+ // XXX Poor coverage.
+
+ {
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->elideMode(), m);
+ QCOMPARE(textObject->width(), 100.);
+
+ delete textObject;
+ }
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->elideMode(), m);
+ QCOMPARE(textObject->width(), 100.);
+
+ delete textObject;
+ }
+
+ // richtext - does nothing
+ for (int i = 0; i < richText.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->elideMode(), m);
+ QCOMPARE(textObject->width(), 100.);
+
+ delete textObject;
+ }
+ }
+}
+
+void tst_qsgtext::textFormat()
+{
+ {
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QVERIFY(textObject->textFormat() == QSGText::RichText);
+
+ delete textObject;
+ }
+ {
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QVERIFY(textObject->textFormat() == QSGText::PlainText);
+
+ delete textObject;
+ }
+}
+
+
+void tst_qsgtext::alignments_data()
+{
+ QTest::addColumn<int>("hAlign");
+ QTest::addColumn<int>("vAlign");
+ QTest::addColumn<QString>("expectfile");
+
+ QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << SRCDIR "/data/alignments_lt.png";
+ QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << SRCDIR "/data/alignments_rt.png";
+ QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << SRCDIR "/data/alignments_ct.png";
+
+ QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << SRCDIR "/data/alignments_lb.png";
+ QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << SRCDIR "/data/alignments_rb.png";
+ QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << SRCDIR "/data/alignments_cb.png";
+
+ QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << SRCDIR "/data/alignments_lc.png";
+ QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << SRCDIR "/data/alignments_rc.png";
+ QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << SRCDIR "/data/alignments_cc.png";
+}
+
+
+void tst_qsgtext::alignments()
+{
+ QFETCH(int, hAlign);
+ QFETCH(int, vAlign);
+ QFETCH(QString, expectfile);
+
+#ifdef Q_WS_X11
+ // Font-specific, but not likely platform-specific, so only test on one platform
+ QFont fn;
+ fn.setRawName("-misc-fixed-medium-r-*-*-8-*-*-*-*-*-*-*");
+ QApplication::setFont(fn);
+#endif
+
+ QSGView *canvas = createView(SRCDIR "/data/alignments.qml");
+
+ canvas->show();
+ QApplication::setActiveWindow(canvas);
+ QTest::qWaitForWindowShown(canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
+
+ QObject *ob = canvas->rootObject();
+ QVERIFY(ob != 0);
+ ob->setProperty("horizontalAlignment",hAlign);
+ ob->setProperty("verticalAlignment",vAlign);
+ QTRY_COMPARE(ob->property("running").toBool(),false);
+ QImage actual(canvas->width(), canvas->height(), QImage::Format_RGB32);
+ actual.fill(qRgb(255,255,255));
+ QPainter p(&actual);
+ canvas->render(&p);
+
+ QImage expect(expectfile);
+
+#ifdef Q_WS_X11
+ // Font-specific, but not likely platform-specific, so only test on one platform
+ if (QApplicationPrivate::graphics_system_name == "raster" || QApplicationPrivate::graphics_system_name == "") {
+ QCOMPARE(actual,expect);
+ }
+#endif
+
+ delete canvas;
+}
+
+//the alignment tests may be trivial o.oa
+void tst_qsgtext::horizontalAlignment()
+{
+ //test one align each, and then test if two align fails.
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
+
+ delete textObject;
+ }
+ }
+
+ for (int i = 0; i < richText.size(); i++)
+ {
+ for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
+
+ delete textObject;
+ }
+ }
+
+}
+
+void tst_qsgtext::horizontalAlignment_RightToLeft()
+{
+ QSGView *canvas = createView(SRCDIR "/data/horizontalAlignment_RightToLeft.qml");
+ QSGText *text = canvas->rootObject()->findChild<QSGText*>("text");
+ QVERIFY(text != 0);
+ canvas->show();
+
+ QSGTextPrivate *textPrivate = QSGTextPrivate::get(text);
+ QVERIFY(textPrivate != 0);
+
+ // implicit alignment should follow the reading direction of RTL text
+ QCOMPARE(text->hAlign(), QSGText::AlignRight);
+ QCOMPARE(text->effectiveHAlign(), text->hAlign());
+ QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
+
+ // explicitly left aligned text
+ text->setHAlign(QSGText::AlignLeft);
+ QCOMPARE(text->hAlign(), QSGText::AlignLeft);
+ QCOMPARE(text->effectiveHAlign(), text->hAlign());
+ QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
+
+ // explicitly right aligned text
+ text->setHAlign(QSGText::AlignRight);
+ QCOMPARE(text->hAlign(), QSGText::AlignRight);
+ QCOMPARE(text->effectiveHAlign(), text->hAlign());
+ QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
+
+ // change to rich text
+ QString textString = text->text();
+ text->setText(QString("<i>") + textString + QString("</i>"));
+ text->setTextFormat(QSGText::RichText);
+ text->resetHAlign();
+
+ // implicitly aligned rich text should follow the reading direction of text
+ QCOMPARE(text->hAlign(), QSGText::AlignRight);
+ QCOMPARE(text->effectiveHAlign(), text->hAlign());
+ QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft);
+
+ // explicitly left aligned rich text
+ text->setHAlign(QSGText::AlignLeft);
+ QCOMPARE(text->hAlign(), QSGText::AlignLeft);
+ QCOMPARE(text->effectiveHAlign(), text->hAlign());
+ QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignRight);
+
+ // explicitly right aligned rich text
+ text->setHAlign(QSGText::AlignRight);
+ QCOMPARE(text->hAlign(), QSGText::AlignRight);
+ QCOMPARE(text->effectiveHAlign(), text->hAlign());
+ QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft);
+
+ text->setText(textString);
+ text->setTextFormat(QSGText::PlainText);
+
+ // explicitly center aligned
+ text->setHAlign(QSGText::AlignHCenter);
+ QCOMPARE(text->hAlign(), QSGText::AlignHCenter);
+ QCOMPARE(text->effectiveHAlign(), text->hAlign());
+ QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
+ QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > canvas->width()/2);
+
+ // reseted alignment should go back to following the text reading direction
+ text->resetHAlign();
+ QCOMPARE(text->hAlign(), QSGText::AlignRight);
+ QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
+
+ // mirror the text item
+ QSGItemPrivate::get(text)->setLayoutMirror(true);
+
+ // mirrored implicit alignment should continue to follow the reading direction of the text
+ QCOMPARE(text->hAlign(), QSGText::AlignRight);
+ QCOMPARE(text->effectiveHAlign(), QSGText::AlignRight);
+ QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
+
+ // mirrored explicitly right aligned behaves as left aligned
+ text->setHAlign(QSGText::AlignRight);
+ QCOMPARE(text->hAlign(), QSGText::AlignRight);
+ QCOMPARE(text->effectiveHAlign(), QSGText::AlignLeft);
+ QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
+
+ // mirrored explicitly left aligned behaves as right aligned
+ text->setHAlign(QSGText::AlignLeft);
+ QCOMPARE(text->hAlign(), QSGText::AlignLeft);
+ QCOMPARE(text->effectiveHAlign(), QSGText::AlignRight);
+ QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
+
+ // disable mirroring
+ QSGItemPrivate::get(text)->setLayoutMirror(false);
+ text->resetHAlign();
+
+ // English text should be implicitly left aligned
+ text->setText("Hello world!");
+ QCOMPARE(text->hAlign(), QSGText::AlignLeft);
+ QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
+
+#ifndef Q_OS_MAC // QTBUG-18040
+ // empty text with implicit alignment follows the system locale-based
+ // keyboard input direction from QApplication::keyboardInputDirection
+ text->setText("");
+ QCOMPARE(text->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
+ QSGText::AlignLeft : QSGText::AlignRight);
+ text->setHAlign(QSGText::AlignRight);
+ QCOMPARE(text->hAlign(), QSGText::AlignRight);
+#endif
+
+ delete canvas;
+
+#ifndef Q_OS_MAC // QTBUG-18040
+ // alignment of Text with no text set to it
+ QString componentStr = "import QtQuick 2.0\nText {}";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+ QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
+ QSGText::AlignLeft : QSGText::AlignRight);
+ delete textObject;
+#endif
+}
+
+void tst_qsgtext::verticalAlignment()
+{
+ //test one align each, and then test if two align fails.
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
+
+ delete textObject;
+ }
+ }
+
+ for (int i = 0; i < richText.size(); i++)
+ {
+ for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
+
+ delete textObject;
+ }
+ }
+
+}
+
+void tst_qsgtext::font()
+{
+ //test size, then bold, then italic, then family
+ {
+ QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->font().pointSize(), 40);
+ QCOMPARE(textObject->font().bold(), false);
+ QCOMPARE(textObject->font().italic(), false);
+
+ delete textObject;
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->font().pixelSize(), 40);
+ QCOMPARE(textObject->font().bold(), false);
+ QCOMPARE(textObject->font().italic(), false);
+
+ delete textObject;
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->font().bold(), true);
+ QCOMPARE(textObject->font().italic(), false);
+
+ delete textObject;
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->font().italic(), true);
+ QCOMPARE(textObject->font().bold(), false);
+
+ delete textObject;
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->font().family(), QString("Helvetica"));
+ QCOMPARE(textObject->font().bold(), false);
+ QCOMPARE(textObject->font().italic(), false);
+
+ delete textObject;
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->font().family(), QString(""));
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::style()
+{
+ //test style
+ for (int i = 0; i < styles.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE((int)textObject->style(), (int)styles.at(i));
+ QCOMPARE(textObject->styleColor(), QColor("white"));
+
+ delete textObject;
+ }
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QRectF brPre = textObject->boundingRect();
+ textObject->setStyle(QSGText::Outline);
+ QRectF brPost = textObject->boundingRect();
+
+ QVERIFY(brPre.width() < brPost.width());
+ QVERIFY(brPre.height() < brPost.height());
+
+ delete textObject;
+}
+
+void tst_qsgtext::color()
+{
+ //test style
+ for (int i = 0; i < colorStrings.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
+ QCOMPARE(textObject->styleColor(), QColor());
+
+ delete textObject;
+ }
+
+ for (int i = 0; i < colorStrings.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
+ // default color to black?
+ QCOMPARE(textObject->color(), QColor("black"));
+
+ delete textObject;
+ }
+
+ for (int i = 0; i < colorStrings.size(); i++)
+ {
+ for (int j = 0; j < colorStrings.size(); j++)
+ {
+ QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; styleColor: \"" + colorStrings.at(j) + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
+ QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
+
+ delete textObject;
+ }
+ }
+ {
+ QString colorStr = "#AA001234";
+ QColor testColor("#001234");
+ testColor.setAlpha(170);
+
+ QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QCOMPARE(textObject->color(), testColor);
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::smooth()
+{
+ for (int i = 0; i < standard.size(); i++)
+ {
+ {
+ QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+ QCOMPARE(textObject->smooth(), true);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+ QCOMPARE(textObject->smooth(), false);
+
+ delete textObject;
+ }
+ }
+ for (int i = 0; i < richText.size(); i++)
+ {
+ {
+ QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+ QCOMPARE(textObject->smooth(), true);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+ QCOMPARE(textObject->smooth(), false);
+
+ delete textObject;
+ }
+ }
+}
+
+void tst_qsgtext::weight()
+{
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Normal);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Bold);
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::underline()
+{
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().underline(), false);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { font.underline: true; text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().underline(), true);
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::overline()
+{
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().overline(), false);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { font.overline: true; text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().overline(), true);
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::strikeout()
+{
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().strikeOut(), false);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { font.strikeout: true; text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().strikeOut(), true);
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::capitalization()
+{
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::MixedCase);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllUppercase);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllLowercase);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::SmallCaps);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::Capitalize);
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::letterSpacing()
+{
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().letterSpacing(), 0.0);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().letterSpacing(), -2.);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().letterSpacing(), 3.);
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::wordSpacing()
+{
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().wordSpacing(), 0.0);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().wordSpacing(), -50.);
+
+ delete textObject;
+ }
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QCOMPARE(textObject->font().wordSpacing(), 200.);
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::QTBUG_12291()
+{
+ QSGView *canvas = createView(SRCDIR "/data/rotated.qml");
+
+ canvas->show();
+ QApplication::setActiveWindow(canvas);
+ QTest::qWaitForWindowShown(canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
+
+ QObject *ob = canvas->rootObject();
+ QVERIFY(ob != 0);
+
+ QSGText *text = ob->findChild<QSGText*>("text");
+ QVERIFY(text);
+ QVERIFY(text->boundingRect().isValid());
+
+ delete canvas;
+}
+
+class EventSender : public QSGItem
+{
+public:
+ void sendEvent(QEvent *event) {
+ if (event->type() == QEvent::GraphicsSceneMousePress)
+ mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(event));
+ else if (event->type() == QEvent::GraphicsSceneMouseRelease)
+ mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(event));
+ else
+ qWarning() << "Trying to send unsupported event type";
+ }
+};
+
+class LinkTest : public QObject
+{
+ Q_OBJECT
+public:
+ LinkTest() {}
+
+ QString link;
+
+public slots:
+ void linkClicked(QString l) { link = l; }
+};
+
+void tst_qsgtext::clickLink()
+{
+ {
+ QString componentStr = "import QtQuick 2.0\nText { text: \"<a href=\\\"http://qt.nokia.com\\\">Hello world!</a>\" }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+
+ LinkTest test;
+ QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
+
+ {
+ QGraphicsSceneMouseEvent me(QEvent::GraphicsSceneMousePress);
+ me.setPos(QPointF(textObject->x()/2, textObject->y()/2));
+ me.setButton(Qt::LeftButton);
+ static_cast<EventSender*>(static_cast<QSGItem*>(textObject))->sendEvent(&me);
+ }
+
+ {
+ QGraphicsSceneMouseEvent me(QEvent::GraphicsSceneMouseRelease);
+ me.setPos(QPointF(textObject->x()/2, textObject->y()/2));
+ me.setButton(Qt::LeftButton);
+ static_cast<EventSender*>(static_cast<QSGItem*>(textObject))->sendEvent(&me);
+ }
+
+ QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
+
+ delete textObject;
+ }
+}
+
+void tst_qsgtext::embeddedImages_data()
+{
+ QTest::addColumn<QUrl>("qmlfile");
+ QTest::addColumn<QString>("error");
+ QTest::newRow("local") << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesLocal.qml") << "";
+ QTest::newRow("local-error") << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesLocalError.qml")
+ << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesLocalError.qml").toString()+":3:1: QML Text: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/http/notexists.png").toString();
+ QTest::newRow("remote") << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesRemote.qml") << "";
+ QTest::newRow("remote-error") << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesRemoteError.qml")
+ << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error downloading http://127.0.0.1:14453/notexists.png - server replied: Not found";
+}
+
+void tst_qsgtext::embeddedImages()
+{
+ // Tests QTBUG-9900
+
+ QFETCH(QUrl, qmlfile);
+ QFETCH(QString, error);
+
+ TestHTTPServer server(14453);
+ server.serveDirectory(SRCDIR "/data/http");
+
+ if (!error.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
+
+ QDeclarativeComponent textComponent(&engine, qmlfile);
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+
+ QTRY_COMPARE(textObject->resourcesLoading(), 0);
+
+ QPixmap pm(SRCDIR "/data/http/exists.png");
+ if (error.isEmpty()) {
+ QCOMPARE(textObject->width(), double(pm.width()));
+ QCOMPARE(textObject->height(), double(pm.height()));
+ } else {
+ QVERIFY(16 != pm.width()); // check test is effective
+ QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
+ QCOMPARE(textObject->height(), 16.0);
+ }
+
+ delete textObject;
+}
+
+void tst_qsgtext::lineCount()
+{
+ QSGView *canvas = createView(SRCDIR "/data/lineCount.qml");
+
+ QSGText *myText = canvas->rootObject()->findChild<QSGText*>("myText");
+ QVERIFY(myText != 0);
+
+ QVERIFY(myText->lineCount() > 1);
+ QVERIFY(!myText->truncated());
+ QCOMPARE(myText->maximumLineCount(), INT_MAX);
+
+ myText->setMaximumLineCount(2);
+ QCOMPARE(myText->lineCount(), 2);
+ QCOMPARE(myText->truncated(), true);
+ QCOMPARE(myText->maximumLineCount(), 2);
+
+ myText->resetMaximumLineCount();
+ QCOMPARE(myText->maximumLineCount(), INT_MAX);
+ QCOMPARE(myText->truncated(), false);
+
+ myText->setElideMode(QSGText::ElideRight);
+ myText->setMaximumLineCount(2);
+ QCOMPARE(myText->lineCount(), 2);
+ QCOMPARE(myText->truncated(), true);
+ QCOMPARE(myText->maximumLineCount(), 2);
+
+ delete canvas;
+}
+
+void tst_qsgtext::lineHeight()
+{
+ QSGView *canvas = createView(SRCDIR "/data/lineHeight.qml");
+
+ QSGText *myText = canvas->rootObject()->findChild<QSGText*>("myText");
+ QVERIFY(myText != 0);
+
+ QVERIFY(myText->lineHeight() == 1);
+ QVERIFY(myText->lineHeightMode() == QSGText::ProportionalHeight);
+
+ qreal h = myText->height();
+ myText->setLineHeight(1.5);
+ QVERIFY(myText->height() == h * 1.5);
+
+ myText->setLineHeightMode(QSGText::FixedHeight);
+ myText->setLineHeight(20);
+ QCOMPARE(myText->height(), myText->lineCount() * 20.0);
+
+ myText->setText("Lorem ipsum sit <b>amet</b>, consectetur adipiscing elit. Integer felis nisl, varius in pretium nec, venenatis non erat. Proin lobortis interdum dictum.");
+ myText->setLineHeightMode(QSGText::ProportionalHeight);
+ myText->setLineHeight(1.0);
+
+ qreal h2 = myText->height();
+ myText->setLineHeight(2.0);
+ QEXPECT_FAIL("", "QTBUG-17325", Continue);
+ QVERIFY(myText->height() == h2 * 2.0);
+
+ myText->setLineHeightMode(QSGText::FixedHeight);
+ myText->setLineHeight(10);
+ QEXPECT_FAIL("", "QTBUG-17325", Continue);
+ QCOMPARE(myText->height(), myText->lineCount() * 10.0);
+
+ delete canvas;
+}
+
+void tst_qsgtext::implicitSize_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QString>("wrap");
+ QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "Text.NoWrap";
+ QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "Text.NoWrap";
+ QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "Text.Wrap";
+ QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "Text.Wrap";
+}
+
+void tst_qsgtext::implicitSize()
+{
+ QFETCH(QString, text);
+ QFETCH(QString, wrap);
+ QString componentStr = "import QtQuick 2.0\nText { text: \"" + text + "\"; width: 50; wrapMode: " + wrap + " }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
+
+ QVERIFY(textObject->width() < textObject->implicitWidth());
+ QVERIFY(textObject->height() == textObject->implicitHeight());
+
+ textObject->resetWidth();
+ QVERIFY(textObject->width() == textObject->implicitWidth());
+ QVERIFY(textObject->height() == textObject->implicitHeight());
+
+ delete textObject;
+}
+
+void tst_qsgtext::testQtQuick11Attributes()
+{
+ QFETCH(QString, code);
+ QFETCH(QString, warning);
+ QFETCH(QString, error);
+
+ QDeclarativeEngine engine;
+ QObject *obj;
+
+ QDeclarativeComponent valid(&engine);
+ valid.setData("import QtQuick 2.0; Text { " + code.toUtf8() + " }", QUrl(""));
+ obj = valid.create();
+ QVERIFY(obj);
+ QVERIFY(valid.errorString().isEmpty());
+ delete obj;
+
+ QDeclarativeComponent invalid(&engine);
+ invalid.setData("import QtQuick 1.0; Text { " + code.toUtf8() + " }", QUrl(""));
+ QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
+ obj = invalid.create();
+ QCOMPARE(invalid.errorString(), error);
+ delete obj;
+}
+
+void tst_qsgtext::testQtQuick11Attributes_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("maximumLineCount") << "maximumLineCount: 4"
+ << "QDeclarativeComponent: Component is not ready"
+ << ":1 \"Text.maximumLineCount\" is not available in QtQuick 1.0.\n";
+
+ QTest::newRow("lineHeight") << "lineHeight: 2"
+ << "QDeclarativeComponent: Component is not ready"
+ << ":1 \"Text.lineHeight\" is not available in QtQuick 1.0.\n";
+
+ QTest::newRow("lineHeightMode") << "lineHeightMode: Text.ProportionalHeight"
+ << "QDeclarativeComponent: Component is not ready"
+ << ":1 \"Text.lineHeightMode\" is not available in QtQuick 1.0.\n";
+
+ QTest::newRow("lineCount") << "property int foo: lineCount"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: lineCount"
+ << "";
+
+ QTest::newRow("truncated") << "property bool foo: truncated"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: truncated"
+ << "";
+}
+
+void tst_qsgtext::qtbug_14734()
+{
+ QSGView *canvas = createView(SRCDIR "/data/qtbug_14734.qml");
+ QVERIFY(canvas);
+
+ canvas->show();
+ QApplication::setActiveWindow(canvas);
+ QTest::qWaitForWindowShown(canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
+
+ delete canvas;
+}
+
+QTEST_MAIN(tst_qsgtext)
+
+#include "tst_qsgtext.moc"
diff --git a/tests/auto/declarative/qsgtextedit/data/CursorRect.qml b/tests/auto/declarative/qsgtextedit/data/CursorRect.qml
new file mode 100644
index 0000000000..cae3e63b72
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/CursorRect.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+ objectName: "myEdit"
+ width: 50
+ text: "This is a long piece of text"
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/alignments.qml b/tests/auto/declarative/qsgtextedit/data/alignments.qml
new file mode 100644
index 0000000000..7d365da8cb
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/alignments.qml
@@ -0,0 +1,41 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: top
+ width: 70; height: 70;
+
+ property alias horizontalAlignment: t.horizontalAlignment
+ property alias verticalAlignment: t.verticalAlignment
+ property alias wrapMode: t.wrapMode
+ property alias running: timer.running
+ property string txt: "Test"
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 40
+ height: 40
+ color: "green"
+
+ TextEdit {
+ id: t
+
+ anchors.fill: parent
+ horizontalAlignment: TextEdit.AlignRight
+ verticalAlignment: TextEdit.AlignBottom
+ wrapMode: TextEdit.WordWrap
+ text: top.txt
+ }
+ Timer {
+ id: timer
+
+ interval: 1
+ running: true
+ repeat: true
+ onTriggered: {
+ top.txt = top.txt + "<br>more " + top.txt.length;
+ if (top.txt.length > 50)
+ running = false
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/alignments_cb.png b/tests/auto/declarative/qsgtextedit/data/alignments_cb.png
new file mode 100644
index 0000000000..99de2192de
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/alignments_cb.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextedit/data/alignments_cc.png b/tests/auto/declarative/qsgtextedit/data/alignments_cc.png
new file mode 100644
index 0000000000..cb85251180
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/alignments_cc.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextedit/data/alignments_ct.png b/tests/auto/declarative/qsgtextedit/data/alignments_ct.png
new file mode 100644
index 0000000000..ddca549c82
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/alignments_ct.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextedit/data/alignments_lb.png b/tests/auto/declarative/qsgtextedit/data/alignments_lb.png
new file mode 100644
index 0000000000..1b50a81f3d
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/alignments_lb.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextedit/data/alignments_lc.png b/tests/auto/declarative/qsgtextedit/data/alignments_lc.png
new file mode 100644
index 0000000000..f041b868f8
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/alignments_lc.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextedit/data/alignments_lt.png b/tests/auto/declarative/qsgtextedit/data/alignments_lt.png
new file mode 100644
index 0000000000..c75e0d158e
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/alignments_lt.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextedit/data/alignments_rb.png b/tests/auto/declarative/qsgtextedit/data/alignments_rb.png
new file mode 100644
index 0000000000..b06a5da715
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/alignments_rb.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextedit/data/alignments_rc.png b/tests/auto/declarative/qsgtextedit/data/alignments_rc.png
new file mode 100644
index 0000000000..e468857cd0
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/alignments_rc.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextedit/data/alignments_rt.png b/tests/auto/declarative/qsgtextedit/data/alignments_rt.png
new file mode 100644
index 0000000000..576715ffce
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/alignments_rt.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextedit/data/cursorTest.qml b/tests/auto/declarative/qsgtextedit/data/cursorTest.qml
new file mode 100644
index 0000000000..e734fc141c
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/cursorTest.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Rectangle { width: 300; height: 300; color: "white"
+ TextEdit { text: "Hello world!"; id: textEditObject; objectName: "textEditObject"
+ resources: [ Component { id:cursor; Item { id:cursorInstance; objectName: "cursorInstance" } } ]
+ cursorDelegate: cursor
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/cursorVisible.qml b/tests/auto/declarative/qsgtextedit/data/cursorVisible.qml
new file mode 100644
index 0000000000..49e9386947
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/cursorVisible.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+Item {
+ width: 100
+ height: 20
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/geometrySignals.qml b/tests/auto/declarative/qsgtextedit/data/geometrySignals.qml
new file mode 100644
index 0000000000..3dbe61c74b
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/geometrySignals.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ width: 400; height: 500;
+ property int bindingWidth: text.width
+ property int bindingHeight: text.height
+
+ TextInput {
+ id: text
+ anchors.fill: parent
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/horizontalAlignment_RightToLeft.qml b/tests/auto/declarative/qsgtextedit/data/horizontalAlignment_RightToLeft.qml
new file mode 100644
index 0000000000..74592fed7f
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/horizontalAlignment_RightToLeft.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: top
+ width: 200; height: 70;
+
+ property alias horizontalAlignment: text.horizontalAlignment
+ property string text: "اختبا"
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 200
+ height: 20
+ color: "green"
+
+ TextEdit {
+ id: text
+ objectName: "text"
+ anchors.fill: parent
+ text: top.text
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/http/ErrItem.qml b/tests/auto/declarative/qsgtextedit/data/http/ErrItem.qml
new file mode 100644
index 0000000000..68c0e0c093
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/http/ErrItem.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Item{
+ Fungus{
+ palatable: false;
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/http/NormItem.qml b/tests/auto/declarative/qsgtextedit/data/http/NormItem.qml
new file mode 100644
index 0000000000..2e4c1ed440
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/http/NormItem.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+Item {
+ objectName: "delegateOkay"
+ Rectangle { }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTest.qml b/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTest.qml
new file mode 100644
index 0000000000..be4526e22b
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTest.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+
+Rectangle { width: 300; height: 300; color: "white"
+ resources: [
+ Component { id:cursorFail; FailItem { objectName: "delegateFail" } },
+ Component { id:cursorWait; WaitItem { objectName: "delegateSlow" } },
+ Component { id:cursorNorm; NormItem { objectName: "delegateOkay" } },
+ Component { id:cursorErr; ErrItem { objectName: "delegateErrorA" } }
+ ]
+ TextEdit {
+ cursorDelegate: cursorFail
+ }
+ TextEdit {
+ cursorDelegate: cursorWait
+ }
+ TextEdit {
+ cursorDelegate: cursorNorm
+ }
+ TextEdit {
+ cursorDelegate: cursorErr
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestFail1.qml b/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestFail1.qml
new file mode 100644
index 0000000000..1d7763f913
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestFail1.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Rectangle { width: 300; height: 300; color: "white"
+ resources: [
+ Component { id:cursorFail; FailItem { objectName: "delegateFail" } },
+ Component { id:cursorWait; WaitItem { objectName: "delegateSlow" } },
+ Component { id:cursorNorm; NormItem { objectName: "delegateOkay" } }
+ ]
+ TextEdit {
+ cursorDelegate: cursorFail
+ }
+ TextEdit {
+ cursorDelegate: cursorWait
+ }
+ TextEdit {
+ cursorDelegate: cursorNorm
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestFail2.qml b/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestFail2.qml
new file mode 100644
index 0000000000..c82ec02e68
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestFail2.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Rectangle { width: 300; height: 300; color: "white"
+ resources: [
+ Component { id:cursorWait; WaitItem { objectName: "delegateSlow" } },
+ Component { id:cursorNorm; NormItem { objectName: "delegateOkay" } },
+ Component { id:cursorErr; ErrItem { objectName: "delegateErrorA" } }
+ ]
+ TextEdit {
+ cursorDelegate: cursorWait
+ }
+ TextEdit {
+ cursorDelegate: cursorNorm
+ }
+ TextEdit {
+ cursorDelegate: cursorErr
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestPass.qml b/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestPass.qml
new file mode 100644
index 0000000000..96d582c95d
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/http/cursorHttpTestPass.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Rectangle { width: 300; height: 300; color: "white"
+ resources: [
+ Component { id:cursorWait; WaitItem { objectName: "delegateSlow" } },
+ Component { id:cursorNorm; NormItem { objectName: "delegateOkay" } }
+ ]
+ TextEdit {
+ cursorDelegate: cursorWait
+ text: "Hello"
+ }
+ TextEdit {
+ objectName: "textEditObject"
+ cursorDelegate: cursorNorm
+ focus: true;
+ text: "Hello"
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/http/qmldir b/tests/auto/declarative/qsgtextedit/data/http/qmldir
new file mode 100644
index 0000000000..886e6ffec0
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/http/qmldir
@@ -0,0 +1,4 @@
+ErrItem ErrItem.qml
+NormItem NormItem.qml
+FailItem FailItem.qml
+WaitItem WaitItem.qml
diff --git a/tests/auto/declarative/qsgtextedit/data/httpfail/FailItem.qml b/tests/auto/declarative/qsgtextedit/data/httpfail/FailItem.qml
new file mode 100644
index 0000000000..8161843479
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/httpfail/FailItem.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+ Rectangle { }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/httpslow/WaitItem.qml b/tests/auto/declarative/qsgtextedit/data/httpslow/WaitItem.qml
new file mode 100644
index 0000000000..8161843479
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/httpslow/WaitItem.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+ Rectangle { }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/inputContext.qml b/tests/auto/declarative/qsgtextedit/data/inputContext.qml
new file mode 100644
index 0000000000..a37c77e3bf
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/inputContext.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextEdit {
+ width: 200
+ text: "supercalifra"
+ focus: true
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/inputMethodEvent.qml b/tests/auto/declarative/qsgtextedit/data/inputMethodEvent.qml
new file mode 100644
index 0000000000..e3f629ce3e
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/inputMethodEvent.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/inputmethodhints.qml b/tests/auto/declarative/qsgtextedit/data/inputmethodhints.qml
new file mode 100644
index 0000000000..dec3b978e7
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/inputmethodhints.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+TextEdit {
+ text: "Hello world!"
+ inputMethodHints: Qt.ImhNoPredictiveText
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/mouseselection_default.qml b/tests/auto/declarative/qsgtextedit/data/mouseselection_default.qml
new file mode 100644
index 0000000000..ac32f4ced7
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/mouseselection_default.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: false
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/mouseselection_false.qml b/tests/auto/declarative/qsgtextedit/data/mouseselection_false.qml
new file mode 100644
index 0000000000..ac32f4ced7
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/mouseselection_false.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: false
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/mouseselection_false_words.qml b/tests/auto/declarative/qsgtextedit/data/mouseselection_false_words.qml
new file mode 100644
index 0000000000..ac32f4ced7
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/mouseselection_false_words.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: false
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/mouseselection_true.qml b/tests/auto/declarative/qsgtextedit/data/mouseselection_true.qml
new file mode 100644
index 0000000000..7c7cb0b6fc
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/mouseselection_true.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: true
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/mouseselection_true_words.qml b/tests/auto/declarative/qsgtextedit/data/mouseselection_true_words.qml
new file mode 100644
index 0000000000..7c7cb0b6fc
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/mouseselection_true_words.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: true
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/mouseselectionmode_characters.qml b/tests/auto/declarative/qsgtextedit/data/mouseselectionmode_characters.qml
new file mode 100644
index 0000000000..c1fe42fd57
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/mouseselectionmode_characters.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: true
+ mouseSelectionMode: TextEdit.SelectCharacters
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/mouseselectionmode_default.qml b/tests/auto/declarative/qsgtextedit/data/mouseselectionmode_default.qml
new file mode 100644
index 0000000000..7c7cb0b6fc
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/mouseselectionmode_default.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: true
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/mouseselectionmode_words.qml b/tests/auto/declarative/qsgtextedit/data/mouseselectionmode_words.qml
new file mode 100644
index 0000000000..0a372bbf83
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/mouseselectionmode_words.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: true
+ mouseSelectionMode: TextEdit.SelectWords
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/navigation.qml b/tests/auto/declarative/qsgtextedit/data/navigation.qml
new file mode 100644
index 0000000000..0201c62b3c
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/navigation.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Rectangle {
+ property variant myInput: input
+
+ width: 800; height: 600; color: "blue"
+
+ Item {
+ id: firstItem;
+ KeyNavigation.right: input
+ }
+
+ TextEdit { id: input; focus: true
+ KeyNavigation.left: firstItem
+ KeyNavigation.right: lastItem
+ KeyNavigation.up: firstItem
+ KeyNavigation.down: lastItem
+ text: "a"
+ }
+ Item {
+ id: lastItem
+ KeyNavigation.left: input
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/openInputPanel.qml b/tests/auto/declarative/qsgtextedit/data/openInputPanel.qml
new file mode 100644
index 0000000000..8998e55abb
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/openInputPanel.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+TextEdit {
+ text: "Hello world"
+ focus: false
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/positionAt.qml b/tests/auto/declarative/qsgtextedit/data/positionAt.qml
new file mode 100644
index 0000000000..19093281fe
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/positionAt.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+TextEdit {
+ focus: true
+ objectName: "myInput"
+ width: 50
+ height: 25
+ text: "This is\n a long piece of text"
+}
diff --git a/tests/auto/declarative/qsgtextedit/data/readOnly.qml b/tests/auto/declarative/qsgtextedit/data/readOnly.qml
new file mode 100644
index 0000000000..085adba5fb
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/data/readOnly.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Rectangle {
+ property variant myInput: input
+
+ width: 800; height: 600; color: "blue"
+
+ TextEdit { id: input; focus: true
+ readOnly: true
+ text: "I am the very model of a modern major general.\n"
+ }
+}
diff --git a/tests/auto/declarative/qsgtextedit/qsgtextedit.pro b/tests/auto/declarative/qsgtextedit/qsgtextedit.pro
new file mode 100644
index 0000000000..a67658efa0
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/qsgtextedit.pro
@@ -0,0 +1,14 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui network
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qsgtextedit.cpp ../shared/testhttpserver.cpp
+HEADERS += ../shared/testhttpserver.h
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
diff --git a/tests/auto/declarative/qsgtextedit/tst_qsgtextedit.cpp b/tests/auto/declarative/qsgtextedit/tst_qsgtextedit.cpp
new file mode 100644
index 0000000000..5510701962
--- /dev/null
+++ b/tests/auto/declarative/qsgtextedit/tst_qsgtextedit.cpp
@@ -0,0 +1,2388 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtTest/QSignalSpy>
+#include "../../../shared/util.h"
+#include "../shared/testhttpserver.h"
+#include <math.h>
+#include <QFile>
+#include <QTextDocument>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <private/qsgtextedit_p.h>
+#include <private/qsgtextedit_p_p.h>
+#include <QFontMetrics>
+#include <QSGView>
+#include <QDir>
+#include <QStyle>
+#include <QInputContext>
+#include <QClipboard>
+#include <QMimeData>
+#include <private/qapplication_p.h>
+#include <private/qtextcontrol_p.h>
+
+#ifdef Q_WS_MAC
+#include <Carbon/Carbon.h>
+#endif
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+Q_DECLARE_METATYPE(QSGTextEdit::SelectionMode)
+
+QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual)
+{
+ // XXX This will be replaced by some clever persistent platform image store.
+ QString persistent_dir = SRCDIR "/data";
+ QString arch = "unknown-architecture"; // QTest needs to help with this.
+
+ QString expectfile = persistent_dir + QDir::separator() + filebasename + "-" + arch + ".png";
+
+ if (!QFile::exists(expectfile)) {
+ actual.save(expectfile);
+ qWarning() << "created" << expectfile;
+ }
+
+ return expectfile;
+}
+
+
+class tst_qsgtextedit : public QObject
+
+{
+ Q_OBJECT
+public:
+ tst_qsgtextedit();
+
+private slots:
+ void text();
+ void width();
+ void wrap();
+ void textFormat();
+ void alignments();
+ void alignments_data();
+
+ // ### these tests may be trivial
+ void hAlign();
+ void hAlign_RightToLeft();
+ void vAlign();
+ void font();
+ void color();
+ void textMargin();
+ void persistentSelection();
+ void focusOnPress();
+ void selection();
+ void isRightToLeft_data();
+ void isRightToLeft();
+ void keySelection();
+ void moveCursorSelection_data();
+ void moveCursorSelection();
+ void moveCursorSelectionSequence_data();
+ void moveCursorSelectionSequence();
+ void mouseSelection_data();
+ void mouseSelection();
+ void mouseSelectionMode_data();
+ void mouseSelectionMode();
+ void dragMouseSelection();
+ void inputMethodHints();
+
+ void positionAt();
+
+ void cursorDelegate();
+ void cursorVisible();
+ void delegateLoading_data();
+ void delegateLoading();
+ void navigation();
+ void readOnly();
+ void copyAndPaste();
+ void canPaste();
+ void canPasteEmpty();
+ void textInput();
+ void openInputPanelOnClick();
+ void openInputPanelOnFocus();
+ void geometrySignals();
+ void pastingRichText_QTBUG_14003();
+ void implicitSize_data();
+ void implicitSize();
+ void testQtQuick11Attributes();
+ void testQtQuick11Attributes_data();
+
+ void preeditMicroFocus();
+ void inputContextMouseHandler();
+ void inputMethodComposing();
+ void cursorRectangleSize();
+
+private:
+ void simulateKey(QSGView *, int key, Qt::KeyboardModifiers modifiers = 0);
+
+ QStringList standard;
+ QStringList richText;
+
+ QStringList hAlignmentStrings;
+ QStringList vAlignmentStrings;
+
+ QList<Qt::Alignment> vAlignments;
+ QList<Qt::Alignment> hAlignments;
+
+ QStringList colorStrings;
+
+ QDeclarativeEngine engine;
+};
+
+tst_qsgtextedit::tst_qsgtextedit()
+{
+ standard << "the quick brown fox jumped over the lazy dog"
+ << "the quick brown fox\n jumped over the lazy dog"
+ << "Hello, world!"
+ << "!dlrow ,olleH";
+
+ richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
+ << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
+
+ hAlignmentStrings << "AlignLeft"
+ << "AlignRight"
+ << "AlignHCenter";
+
+ vAlignmentStrings << "AlignTop"
+ << "AlignBottom"
+ << "AlignVCenter";
+
+ hAlignments << Qt::AlignLeft
+ << Qt::AlignRight
+ << Qt::AlignHCenter;
+
+ vAlignments << Qt::AlignTop
+ << Qt::AlignBottom
+ << Qt::AlignVCenter;
+
+ colorStrings << "aliceblue"
+ << "antiquewhite"
+ << "aqua"
+ << "darkkhaki"
+ << "darkolivegreen"
+ << "dimgray"
+ << "palevioletred"
+ << "lightsteelblue"
+ << "#000000"
+ << "#AAAAAA"
+ << "#FFFFFF"
+ << "#2AC05F";
+ //
+ // need a different test to do alpha channel test
+ // << "#AA0011DD"
+ // << "#00F16B11";
+ //
+}
+
+void tst_qsgtextedit::text()
+{
+ {
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData("import QtQuick 2.0\nTextEdit { text: \"\" }", QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->text(), QString(""));
+ }
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->text(), standard.at(i));
+ }
+
+ for (int i = 0; i < richText.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QString actual = textEditObject->text();
+ QString expected = richText.at(i);
+ actual.replace(QRegExp(".*<body[^>]*>"),"");
+ actual.replace(QRegExp("(<[^>]*>)+"),"<>");
+ expected.replace(QRegExp("(<[^>]*>)+"),"<>");
+ QCOMPARE(actual.simplified(),expected.simplified());
+ }
+}
+
+void tst_qsgtextedit::width()
+{
+ // uses Font metrics to find the width for standard and document to find the width for rich
+ {
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData("import QtQuick 2.0\nTextEdit { text: \"\" }", QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->width(), 0.0);
+ }
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ QFont f;
+ QFontMetricsF fm(f);
+ qreal metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
+ metricWidth = ceil(metricWidth);
+
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->width(), qreal(metricWidth));
+ }
+
+ for (int i = 0; i < richText.size(); i++)
+ {
+ QTextDocument document;
+ document.setHtml(richText.at(i));
+ document.setDocumentMargin(0);
+
+ int documentWidth = ceil(document.idealWidth());
+
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->width(), qreal(documentWidth));
+ }
+}
+
+void tst_qsgtextedit::wrap()
+{
+ // for specified width and wrap set true
+ {
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData("import QtQuick 2.0\nTextEdit { text: \"\"; wrapMode: TextEdit.WordWrap; width: 300 }", QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->width(), 300.);
+ }
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { wrapMode: TextEdit.WordWrap; width: 300; text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->width(), 300.);
+ }
+
+ for (int i = 0; i < richText.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { wrapMode: TextEdit.WordWrap; width: 300; text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->width(), 300.);
+ }
+
+}
+
+void tst_qsgtextedit::textFormat()
+{
+ {
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData("import QtQuick 2.0\nTextEdit { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
+ QSGTextEdit *textObject = qobject_cast<QSGTextEdit*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QVERIFY(textObject->textFormat() == QSGTextEdit::RichText);
+ }
+ {
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData("import QtQuick 2.0\nTextEdit { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
+ QSGTextEdit *textObject = qobject_cast<QSGTextEdit*>(textComponent.create());
+
+ QVERIFY(textObject != 0);
+ QVERIFY(textObject->textFormat() == QSGTextEdit::PlainText);
+ }
+}
+
+void tst_qsgtextedit::alignments_data()
+{
+ QTest::addColumn<int>("hAlign");
+ QTest::addColumn<int>("vAlign");
+ QTest::addColumn<QString>("expectfile");
+
+ QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << "alignments_lt";
+ QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << "alignments_rt";
+ QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << "alignments_ct";
+
+ QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << "alignments_lb";
+ QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << "alignments_rb";
+ QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << "alignments_cb";
+
+ QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << "alignments_lc";
+ QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << "alignments_rc";
+ QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << "alignments_cc";
+}
+
+
+void tst_qsgtextedit::alignments()
+{
+ QFETCH(int, hAlign);
+ QFETCH(int, vAlign);
+ QFETCH(QString, expectfile);
+
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/alignments.qml"));
+
+ canvas.show();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+
+ QObject *ob = canvas.rootObject();
+ QVERIFY(ob != 0);
+ ob->setProperty("horizontalAlignment",hAlign);
+ ob->setProperty("verticalAlignment",vAlign);
+ QTRY_COMPARE(ob->property("running").toBool(),false);
+ QImage actual(canvas.width(), canvas.height(), QImage::Format_RGB32);
+ actual.fill(qRgb(255,255,255));
+ QPainter p(&actual);
+ canvas.render(&p);
+
+ expectfile = createExpectedFileIfNotFound(expectfile, actual);
+
+ QImage expect(expectfile);
+
+ QCOMPARE(actual,expect);
+}
+
+
+//the alignment tests may be trivial o.oa
+void tst_qsgtextedit::hAlign()
+{
+ //test one align each, and then test if two align fails.
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ for (int j=0; j < hAlignmentStrings.size(); j++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { horizontalAlignment: \"" + hAlignmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j));
+ }
+ }
+
+ for (int i = 0; i < richText.size(); i++)
+ {
+ for (int j=0; j < hAlignmentStrings.size(); j++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { horizontalAlignment: \"" + hAlignmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j));
+ }
+ }
+
+}
+
+void tst_qsgtextedit::hAlign_RightToLeft()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/horizontalAlignment_RightToLeft.qml"));
+ QSGTextEdit *textEdit = canvas.rootObject()->findChild<QSGTextEdit*>("text");
+ QVERIFY(textEdit != 0);
+ canvas.show();
+
+ // implicit alignment should follow the reading direction of text
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignRight);
+ QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
+
+ // explicitly left aligned
+ textEdit->setHAlign(QSGTextEdit::AlignLeft);
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignLeft);
+ QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
+
+ // explicitly right aligned
+ textEdit->setHAlign(QSGTextEdit::AlignRight);
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignRight);
+ QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
+
+ QString textString = textEdit->text();
+ textEdit->setText(QString("<i>") + textString + QString("</i>"));
+ textEdit->resetHAlign();
+
+ // implicitly aligned rich text should follow the reading direction of RTL text
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignRight);
+ QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
+ QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
+
+ // explicitly left aligned rich text
+ textEdit->setHAlign(QSGTextEdit::AlignLeft);
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignLeft);
+ QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
+ QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
+
+ // explicitly right aligned rich text
+ textEdit->setHAlign(QSGTextEdit::AlignRight);
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignRight);
+ QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign());
+ QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
+
+ textEdit->setText(textString);
+
+ // explicitly center aligned
+ textEdit->setHAlign(QSGTextEdit::AlignHCenter);
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignHCenter);
+ QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
+
+ // reseted alignment should go back to following the text reading direction
+ textEdit->resetHAlign();
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignRight);
+ QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
+
+ // mirror the text item
+ QSGItemPrivate::get(textEdit)->setLayoutMirror(true);
+
+ // mirrored implicit alignment should continue to follow the reading direction of the text
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignRight);
+ QCOMPARE(textEdit->effectiveHAlign(), QSGTextEdit::AlignRight);
+ QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
+
+ // mirrored explicitly right aligned behaves as left aligned
+ textEdit->setHAlign(QSGTextEdit::AlignRight);
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignRight);
+ QCOMPARE(textEdit->effectiveHAlign(), QSGTextEdit::AlignLeft);
+ QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
+
+ // mirrored explicitly left aligned behaves as right aligned
+ textEdit->setHAlign(QSGTextEdit::AlignLeft);
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignLeft);
+ QCOMPARE(textEdit->effectiveHAlign(), QSGTextEdit::AlignRight);
+ QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
+
+ // disable mirroring
+ QSGItemPrivate::get(textEdit)->setLayoutMirror(false);
+ textEdit->resetHAlign();
+
+ // English text should be implicitly left aligned
+ textEdit->setText("Hello world!");
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignLeft);
+ QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
+
+#ifndef Q_OS_MAC // QTBUG-18040
+ // empty text with implicit alignment follows the system locale-based
+ // keyboard input direction from QApplication::keyboardInputDirection
+ textEdit->setText("");
+ QCOMPARE(textEdit->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
+ QSGTextEdit::AlignLeft : QSGTextEdit::AlignRight);
+ if (QApplication::keyboardInputDirection() == Qt::LeftToRight)
+ QVERIFY(textEdit->positionToRectangle(0).x() < canvas.width()/2);
+ else
+ QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
+ textEdit->setHAlign(QSGTextEdit::AlignRight);
+ QCOMPARE(textEdit->hAlign(), QSGTextEdit::AlignRight);
+ QVERIFY(textEdit->positionToRectangle(0).x() > canvas.width()/2);
+#endif
+
+#ifndef Q_OS_MAC // QTBUG-18040
+ // alignment of TextEdit with no text set to it
+ QString componentStr = "import QtQuick 2.0\nTextEdit {}";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGTextEdit *textObject = qobject_cast<QSGTextEdit*>(textComponent.create());
+ QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
+ QSGTextEdit::AlignLeft : QSGTextEdit::AlignRight);
+ delete textObject;
+#endif
+}
+
+void tst_qsgtextedit::vAlign()
+{
+ //test one align each, and then test if two align fails.
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ for (int j=0; j < vAlignmentStrings.size(); j++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { verticalAlignment: \"" + vAlignmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j));
+ }
+ }
+
+ for (int i = 0; i < richText.size(); i++)
+ {
+ for (int j=0; j < vAlignmentStrings.size(); j++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { verticalAlignment: \"" + vAlignmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j));
+ }
+ }
+
+}
+
+void tst_qsgtextedit::font()
+{
+ //test size, then bold, then italic, then family
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { font.pointSize: 40; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->font().pointSize(), 40);
+ QCOMPARE(textEditObject->font().bold(), false);
+ QCOMPARE(textEditObject->font().italic(), false);
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { font.bold: true; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->font().bold(), true);
+ QCOMPARE(textEditObject->font().italic(), false);
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { font.italic: true; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->font().italic(), true);
+ QCOMPARE(textEditObject->font().bold(), false);
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { font.family: \"Helvetica\"; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->font().family(), QString("Helvetica"));
+ QCOMPARE(textEditObject->font().bold(), false);
+ QCOMPARE(textEditObject->font().italic(), false);
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { font.family: \"\"; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->font().family(), QString(""));
+ }
+}
+
+void tst_qsgtextedit::color()
+{
+ //test initial color
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QSGTextEditPrivate *textEditPrivate = static_cast<QSGTextEditPrivate*>(QSGItemPrivate::get(textEditObject));
+
+ QVERIFY(textEditObject);
+ QVERIFY(textEditPrivate);
+ QVERIFY(textEditPrivate->control);
+
+ QPalette pal = textEditPrivate->control->palette();
+ QCOMPARE(textEditPrivate->color, QColor("black"));
+ QCOMPARE(textEditPrivate->color, pal.color(QPalette::Text));
+ }
+ //test normal
+ for (int i = 0; i < colorStrings.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+ //qDebug() << "textEditObject: " << textEditObject->color() << "vs. " << QColor(colorStrings.at(i));
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->color(), QColor(colorStrings.at(i)));
+ }
+
+ //test selection
+ for (int i = 0; i < colorStrings.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { selectionColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->selectionColor(), QColor(colorStrings.at(i)));
+ }
+
+ //test selected text
+ for (int i = 0; i < colorStrings.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { selectedTextColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->selectedTextColor(), QColor(colorStrings.at(i)));
+ }
+
+ {
+ QString colorStr = "#AA001234";
+ QColor testColor("#001234");
+ testColor.setAlpha(170);
+
+ QString componentStr = "import QtQuick 2.0\nTextEdit { color: \"" + colorStr + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->color(), testColor);
+ }
+}
+
+void tst_qsgtextedit::textMargin()
+{
+ for(qreal i=0; i<=10; i+=0.3){
+ QString componentStr = "import QtQuick 2.0\nTextEdit { textMargin: " + QString::number(i) + "; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->textMargin(), i);
+ }
+}
+
+void tst_qsgtextedit::persistentSelection()
+{
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { persistentSelection: true; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->persistentSelection(), true);
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { persistentSelection: false; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->persistentSelection(), false);
+ }
+}
+
+void tst_qsgtextedit::focusOnPress()
+{
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { activeFocusOnPress: true; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->focusOnPress(), true);
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nTextEdit { activeFocusOnPress: false; text: \"Hello World\" }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+ QVERIFY(textEditObject != 0);
+ QCOMPARE(textEditObject->focusOnPress(), false);
+ }
+}
+
+void tst_qsgtextedit::selection()
+{
+ QString testStr = standard[0];//TODO: What should happen for multiline/rich text?
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \""+ testStr +"\"; }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+ QVERIFY(textEditObject != 0);
+
+
+ //Test selection follows cursor
+ for(int i=0; i<= testStr.size(); i++) {
+ textEditObject->setCursorPosition(i);
+ QCOMPARE(textEditObject->cursorPosition(), i);
+ QCOMPARE(textEditObject->selectionStart(), i);
+ QCOMPARE(textEditObject->selectionEnd(), i);
+ QVERIFY(textEditObject->selectedText().isNull());
+ }
+
+ textEditObject->setCursorPosition(0);
+ QVERIFY(textEditObject->cursorPosition() == 0);
+ QVERIFY(textEditObject->selectionStart() == 0);
+ QVERIFY(textEditObject->selectionEnd() == 0);
+ QVERIFY(textEditObject->selectedText().isNull());
+
+ // Verify invalid positions are ignored.
+ textEditObject->setCursorPosition(-1);
+ QVERIFY(textEditObject->cursorPosition() == 0);
+ QVERIFY(textEditObject->selectionStart() == 0);
+ QVERIFY(textEditObject->selectionEnd() == 0);
+ QVERIFY(textEditObject->selectedText().isNull());
+
+ textEditObject->setCursorPosition(textEditObject->text().count()+1);
+ QVERIFY(textEditObject->cursorPosition() == 0);
+ QVERIFY(textEditObject->selectionStart() == 0);
+ QVERIFY(textEditObject->selectionEnd() == 0);
+ QVERIFY(textEditObject->selectedText().isNull());
+
+ //Test selection
+ for(int i=0; i<= testStr.size(); i++) {
+ textEditObject->select(0,i);
+ QCOMPARE(testStr.mid(0,i), textEditObject->selectedText());
+ }
+ for(int i=0; i<= testStr.size(); i++) {
+ textEditObject->select(i,testStr.size());
+ QCOMPARE(testStr.mid(i,testStr.size()-i), textEditObject->selectedText());
+ }
+
+ textEditObject->setCursorPosition(0);
+ QVERIFY(textEditObject->cursorPosition() == 0);
+ QVERIFY(textEditObject->selectionStart() == 0);
+ QVERIFY(textEditObject->selectionEnd() == 0);
+ QVERIFY(textEditObject->selectedText().isNull());
+
+ //Test Error Ignoring behaviour
+ textEditObject->setCursorPosition(0);
+ QVERIFY(textEditObject->selectedText().isNull());
+ textEditObject->select(-10,0);
+ QVERIFY(textEditObject->selectedText().isNull());
+ textEditObject->select(100,101);
+ QVERIFY(textEditObject->selectedText().isNull());
+ textEditObject->select(0,-10);
+ QVERIFY(textEditObject->selectedText().isNull());
+ textEditObject->select(0,100);
+ QVERIFY(textEditObject->selectedText().isNull());
+ textEditObject->select(0,10);
+ QVERIFY(textEditObject->selectedText().size() == 10);
+ textEditObject->select(-10,0);
+ QVERIFY(textEditObject->selectedText().size() == 10);
+ textEditObject->select(100,101);
+ QVERIFY(textEditObject->selectedText().size() == 10);
+ textEditObject->select(0,-10);
+ QVERIFY(textEditObject->selectedText().size() == 10);
+ textEditObject->select(0,100);
+ QVERIFY(textEditObject->selectedText().size() == 10);
+
+ textEditObject->deselect();
+ QVERIFY(textEditObject->selectedText().isNull());
+ textEditObject->select(0,10);
+ QVERIFY(textEditObject->selectedText().size() == 10);
+ textEditObject->deselect();
+ QVERIFY(textEditObject->selectedText().isNull());
+}
+
+void tst_qsgtextedit::isRightToLeft_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<bool>("emptyString");
+ QTest::addColumn<bool>("firstCharacter");
+ QTest::addColumn<bool>("lastCharacter");
+ QTest::addColumn<bool>("middleCharacter");
+ QTest::addColumn<bool>("startString");
+ QTest::addColumn<bool>("midString");
+ QTest::addColumn<bool>("endString");
+
+ const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647};
+ QTest::newRow("Empty") << "" << false << false << false << false << false << false << false;
+ QTest::newRow("Neutral") << "23244242" << false << false << false << false << false << false << false;
+ QTest::newRow("LTR") << "Hello world" << false << false << false << false << false << false << false;
+ QTest::newRow("RTL") << QString::fromUtf16(arabic_str, 11) << false << true << true << true << true << true << true;
+ QTest::newRow("Bidi RTL + LTR + RTL") << QString::fromUtf16(arabic_str, 11) + QString("Hello world") + QString::fromUtf16(arabic_str, 11) << false << true << true << false << true << true << true;
+ QTest::newRow("Bidi LTR + RTL + LTR") << QString("Hello world") + QString::fromUtf16(arabic_str, 11) + QString("Hello world") << false << false << false << true << false << false << false;
+}
+
+void tst_qsgtextedit::isRightToLeft()
+{
+ QFETCH(QString, text);
+ QFETCH(bool, emptyString);
+ QFETCH(bool, firstCharacter);
+ QFETCH(bool, lastCharacter);
+ QFETCH(bool, middleCharacter);
+ QFETCH(bool, startString);
+ QFETCH(bool, midString);
+ QFETCH(bool, endString);
+
+ QSGTextEdit textEdit;
+ textEdit.setText(text);
+
+ // first test that the right string is delivered to the QString::isRightToLeft()
+ QCOMPARE(textEdit.isRightToLeft(0,0), text.mid(0,0).isRightToLeft());
+ QCOMPARE(textEdit.isRightToLeft(0,1), text.mid(0,1).isRightToLeft());
+ QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft());
+ QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft());
+ QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft());
+ QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft());
+ if (text.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start.");
+ QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft());
+
+ // then test that the feature actually works
+ QCOMPARE(textEdit.isRightToLeft(0,0), emptyString);
+ QCOMPARE(textEdit.isRightToLeft(0,1), firstCharacter);
+ QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), lastCharacter);
+ QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter);
+ QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), startString);
+ QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), midString);
+ if (text.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start.");
+ QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), endString);
+}
+
+void tst_qsgtextedit::keySelection()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/navigation.qml"));
+ canvas.show();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+ canvas.setFocus();
+
+ QVERIFY(canvas.rootObject() != 0);
+
+ QSGTextEdit *input = qobject_cast<QSGTextEdit *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
+
+ QVERIFY(input != 0);
+ QTRY_VERIFY(input->hasActiveFocus() == true);
+
+ QSignalSpy spy(input, SIGNAL(selectionChanged()));
+
+ simulateKey(&canvas, Qt::Key_Right, Qt::ShiftModifier);
+ QVERIFY(input->hasActiveFocus() == true);
+ QCOMPARE(input->selectedText(), QString("a"));
+ QCOMPARE(spy.count(), 1);
+ simulateKey(&canvas, Qt::Key_Right);
+ QVERIFY(input->hasActiveFocus() == true);
+ QCOMPARE(input->selectedText(), QString());
+ QCOMPARE(spy.count(), 2);
+ simulateKey(&canvas, Qt::Key_Right);
+ QVERIFY(input->hasActiveFocus() == false);
+ QCOMPARE(input->selectedText(), QString());
+ QCOMPARE(spy.count(), 2);
+
+ simulateKey(&canvas, Qt::Key_Left);
+ QVERIFY(input->hasActiveFocus() == true);
+ QCOMPARE(spy.count(), 2);
+ simulateKey(&canvas, Qt::Key_Left, Qt::ShiftModifier);
+ QVERIFY(input->hasActiveFocus() == true);
+ QCOMPARE(input->selectedText(), QString("a"));
+ QCOMPARE(spy.count(), 3);
+ simulateKey(&canvas, Qt::Key_Left);
+ QVERIFY(input->hasActiveFocus() == true);
+ QCOMPARE(input->selectedText(), QString());
+ QCOMPARE(spy.count(), 4);
+ simulateKey(&canvas, Qt::Key_Left);
+ QVERIFY(input->hasActiveFocus() == false);
+ QCOMPARE(input->selectedText(), QString());
+ QCOMPARE(spy.count(), 4);
+}
+
+void tst_qsgtextedit::moveCursorSelection_data()
+{
+ QTest::addColumn<QString>("testStr");
+ QTest::addColumn<int>("cursorPosition");
+ QTest::addColumn<int>("movePosition");
+ QTest::addColumn<QSGTextEdit::SelectionMode>("mode");
+ QTest::addColumn<int>("selectionStart");
+ QTest::addColumn<int>("selectionEnd");
+ QTest::addColumn<bool>("reversible");
+
+ QTest::newRow("(t)he|characters")
+ << standard[0] << 0 << 1 << QSGTextEdit::SelectCharacters << 0 << 1 << true;
+ QTest::newRow("do(g)|characters")
+ << standard[0] << 43 << 44 << QSGTextEdit::SelectCharacters << 43 << 44 << true;
+ QTest::newRow("jum(p)ed|characters")
+ << standard[0] << 23 << 24 << QSGTextEdit::SelectCharacters << 23 << 24 << true;
+ QTest::newRow("jumped( )over|characters")
+ << standard[0] << 26 << 27 << QSGTextEdit::SelectCharacters << 26 << 27 << true;
+ QTest::newRow("(the )|characters")
+ << standard[0] << 0 << 4 << QSGTextEdit::SelectCharacters << 0 << 4 << true;
+ QTest::newRow("( dog)|characters")
+ << standard[0] << 40 << 44 << QSGTextEdit::SelectCharacters << 40 << 44 << true;
+ QTest::newRow("( jumped )|characters")
+ << standard[0] << 19 << 27 << QSGTextEdit::SelectCharacters << 19 << 27 << true;
+ QTest::newRow("th(e qu)ick|characters")
+ << standard[0] << 2 << 6 << QSGTextEdit::SelectCharacters << 2 << 6 << true;
+ QTest::newRow("la(zy d)og|characters")
+ << standard[0] << 38 << 42 << QSGTextEdit::SelectCharacters << 38 << 42 << true;
+ QTest::newRow("jum(ped ov)er|characters")
+ << standard[0] << 23 << 29 << QSGTextEdit::SelectCharacters << 23 << 29 << true;
+ QTest::newRow("()the|characters")
+ << standard[0] << 0 << 0 << QSGTextEdit::SelectCharacters << 0 << 0 << true;
+ QTest::newRow("dog()|characters")
+ << standard[0] << 44 << 44 << QSGTextEdit::SelectCharacters << 44 << 44 << true;
+ QTest::newRow("jum()ped|characters")
+ << standard[0] << 23 << 23 << QSGTextEdit::SelectCharacters << 23 << 23 << true;
+
+ QTest::newRow("<(t)he>|words")
+ << standard[0] << 0 << 1 << QSGTextEdit::SelectWords << 0 << 3 << true;
+ QTest::newRow("<do(g)>|words")
+ << standard[0] << 43 << 44 << QSGTextEdit::SelectWords << 41 << 44 << true;
+ QTest::newRow("<jum(p)ed>|words")
+ << standard[0] << 23 << 24 << QSGTextEdit::SelectWords << 20 << 26 << true;
+ QTest::newRow("<jumped( )>over|words")
+ << standard[0] << 26 << 27 << QSGTextEdit::SelectWords << 20 << 27 << false;
+ QTest::newRow("jumped<( )over>|words,reversed")
+ << standard[0] << 27 << 26 << QSGTextEdit::SelectWords << 26 << 31 << false;
+ QTest::newRow("<(the )>quick|words")
+ << standard[0] << 0 << 4 << QSGTextEdit::SelectWords << 0 << 4 << false;
+ QTest::newRow("<(the )quick>|words,reversed")
+ << standard[0] << 4 << 0 << QSGTextEdit::SelectWords << 0 << 9 << false;
+ QTest::newRow("<lazy( dog)>|words")
+ << standard[0] << 40 << 44 << QSGTextEdit::SelectWords << 36 << 44 << false;
+ QTest::newRow("lazy<( dog)>|words,reversed")
+ << standard[0] << 44 << 40 << QSGTextEdit::SelectWords << 40 << 44 << false;
+ QTest::newRow("<fox( jumped )>over|words")
+ << standard[0] << 19 << 27 << QSGTextEdit::SelectWords << 16 << 27 << false;
+ QTest::newRow("fox<( jumped )over>|words,reversed")
+ << standard[0] << 27 << 19 << QSGTextEdit::SelectWords << 19 << 31 << false;
+ QTest::newRow("<th(e qu)ick>|words")
+ << standard[0] << 2 << 6 << QSGTextEdit::SelectWords << 0 << 9 << true;
+ QTest::newRow("<la(zy d)og|words>")
+ << standard[0] << 38 << 42 << QSGTextEdit::SelectWords << 36 << 44 << true;
+ QTest::newRow("<jum(ped ov)er>|words")
+ << standard[0] << 23 << 29 << QSGTextEdit::SelectWords << 20 << 31 << true;
+ QTest::newRow("<()>the|words")
+ << standard[0] << 0 << 0 << QSGTextEdit::SelectWords << 0 << 0 << true;
+ QTest::newRow("dog<()>|words")
+ << standard[0] << 44 << 44 << QSGTextEdit::SelectWords << 44 << 44 << true;
+ QTest::newRow("jum<()>ped|words")
+ << standard[0] << 23 << 23 << QSGTextEdit::SelectWords << 23 << 23 << true;
+
+ QTest::newRow("Hello<(,)> |words")
+ << standard[2] << 5 << 6 << QSGTextEdit::SelectWords << 5 << 6 << true;
+ QTest::newRow("Hello<(, )>world|words")
+ << standard[2] << 5 << 7 << QSGTextEdit::SelectWords << 5 << 7 << false;
+ QTest::newRow("Hello<(, )world>|words,reversed")
+ << standard[2] << 7 << 5 << QSGTextEdit::SelectWords << 5 << 12 << false;
+ QTest::newRow("<Hel(lo, )>world|words")
+ << standard[2] << 3 << 7 << QSGTextEdit::SelectWords << 0 << 7 << false;
+ QTest::newRow("<Hel(lo, )world>|words,reversed")
+ << standard[2] << 7 << 3 << QSGTextEdit::SelectWords << 0 << 12 << false;
+ QTest::newRow("<Hel(lo)>,|words")
+ << standard[2] << 3 << 5 << QSGTextEdit::SelectWords << 0 << 5 << true;
+ QTest::newRow("Hello<()>,|words")
+ << standard[2] << 5 << 5 << QSGTextEdit::SelectWords << 5 << 5 << true;
+ QTest::newRow("Hello,<()>|words")
+ << standard[2] << 6 << 6 << QSGTextEdit::SelectWords << 6 << 6 << true;
+ QTest::newRow("Hello<,( )>world|words")
+ << standard[2] << 6 << 7 << QSGTextEdit::SelectWords << 5 << 7 << false;
+ QTest::newRow("Hello,<( )world>|words,reversed")
+ << standard[2] << 7 << 6 << QSGTextEdit::SelectWords << 6 << 12 << false;
+ QTest::newRow("Hello<,( world)>|words")
+ << standard[2] << 6 << 12 << QSGTextEdit::SelectWords << 5 << 12 << false;
+ QTest::newRow("Hello,<( world)>|words,reversed")
+ << standard[2] << 12 << 6 << QSGTextEdit::SelectWords << 6 << 12 << false;
+ QTest::newRow("Hello<,( world!)>|words")
+ << standard[2] << 6 << 13 << QSGTextEdit::SelectWords << 5 << 13 << false;
+ QTest::newRow("Hello,<( world!)>|words,reversed")
+ << standard[2] << 13 << 6 << QSGTextEdit::SelectWords << 6 << 13 << false;
+ QTest::newRow("Hello<(, world!)>|words")
+ << standard[2] << 5 << 13 << QSGTextEdit::SelectWords << 5 << 13 << true;
+ QTest::newRow("world<(!)>|words")
+ << standard[2] << 12 << 13 << QSGTextEdit::SelectWords << 12 << 13 << true;
+ QTest::newRow("world!<()>)|words")
+ << standard[2] << 13 << 13 << QSGTextEdit::SelectWords << 13 << 13 << true;
+ QTest::newRow("world<()>!)|words")
+ << standard[2] << 12 << 12 << QSGTextEdit::SelectWords << 12 << 12 << true;
+
+ QTest::newRow("<(,)>olleH |words")
+ << standard[3] << 7 << 8 << QSGTextEdit::SelectWords << 7 << 8 << true;
+ QTest::newRow("<dlrow( ,)>olleH|words")
+ << standard[3] << 6 << 8 << QSGTextEdit::SelectWords << 1 << 8 << false;
+ QTest::newRow("dlrow<( ,)>olleH|words,reversed")
+ << standard[3] << 8 << 6 << QSGTextEdit::SelectWords << 6 << 8 << false;
+ QTest::newRow("<dlrow( ,ol)leH>|words")
+ << standard[3] << 6 << 10 << QSGTextEdit::SelectWords << 1 << 13 << false;
+ QTest::newRow("dlrow<( ,ol)leH>|words,reversed")
+ << standard[3] << 10 << 6 << QSGTextEdit::SelectWords << 6 << 13 << false;
+ QTest::newRow(",<(ol)leH>,|words")
+ << standard[3] << 8 << 10 << QSGTextEdit::SelectWords << 8 << 13 << true;
+ QTest::newRow(",<()>olleH|words")
+ << standard[3] << 8 << 8 << QSGTextEdit::SelectWords << 8 << 8 << true;
+ QTest::newRow("<()>,olleH|words")
+ << standard[3] << 7 << 7 << QSGTextEdit::SelectWords << 7 << 7 << true;
+ QTest::newRow("<dlrow( )>,olleH|words")
+ << standard[3] << 6 << 7 << QSGTextEdit::SelectWords << 1 << 7 << false;
+ QTest::newRow("dlrow<( ),>olleH|words,reversed")
+ << standard[3] << 7 << 6 << QSGTextEdit::SelectWords << 6 << 8 << false;
+ QTest::newRow("<(dlrow )>,olleH|words")
+ << standard[3] << 1 << 7 << QSGTextEdit::SelectWords << 1 << 7 << false;
+ QTest::newRow("<(dlrow ),>olleH|words,reversed")
+ << standard[3] << 7 << 1 << QSGTextEdit::SelectWords << 1 << 8 << false;
+ QTest::newRow("<(!dlrow )>,olleH|words")
+ << standard[3] << 0 << 7 << QSGTextEdit::SelectWords << 0 << 7 << false;
+ QTest::newRow("<(!dlrow ),>olleH|words,reversed")
+ << standard[3] << 7 << 0 << QSGTextEdit::SelectWords << 0 << 8 << false;
+ QTest::newRow("(!dlrow ,)olleH|words")
+ << standard[3] << 0 << 8 << QSGTextEdit::SelectWords << 0 << 8 << true;
+ QTest::newRow("<(!)>dlrow|words")
+ << standard[3] << 0 << 1 << QSGTextEdit::SelectWords << 0 << 1 << true;
+ QTest::newRow("<()>!dlrow|words")
+ << standard[3] << 0 << 0 << QSGTextEdit::SelectWords << 0 << 0 << true;
+ QTest::newRow("!<()>dlrow|words")
+ << standard[3] << 1 << 1 << QSGTextEdit::SelectWords << 1 << 1 << true;
+}
+
+void tst_qsgtextedit::moveCursorSelection()
+{
+ QFETCH(QString, testStr);
+ QFETCH(int, cursorPosition);
+ QFETCH(int, movePosition);
+ QFETCH(QSGTextEdit::SelectionMode, mode);
+ QFETCH(int, selectionStart);
+ QFETCH(int, selectionEnd);
+ QFETCH(bool, reversible);
+
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \""+ testStr +"\"; }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *texteditObject = qobject_cast<QSGTextEdit*>(textinputComponent.create());
+ QVERIFY(texteditObject != 0);
+
+ texteditObject->setCursorPosition(cursorPosition);
+ texteditObject->moveCursorSelection(movePosition, mode);
+
+ QCOMPARE(texteditObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
+ QCOMPARE(texteditObject->selectionStart(), selectionStart);
+ QCOMPARE(texteditObject->selectionEnd(), selectionEnd);
+
+ if (reversible) {
+ texteditObject->setCursorPosition(movePosition);
+ texteditObject->moveCursorSelection(cursorPosition, mode);
+
+ QCOMPARE(texteditObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
+ QCOMPARE(texteditObject->selectionStart(), selectionStart);
+ QCOMPARE(texteditObject->selectionEnd(), selectionEnd);
+ }
+}
+
+void tst_qsgtextedit::moveCursorSelectionSequence_data()
+{
+ QTest::addColumn<QString>("testStr");
+ QTest::addColumn<int>("cursorPosition");
+ QTest::addColumn<int>("movePosition1");
+ QTest::addColumn<int>("movePosition2");
+ QTest::addColumn<int>("selection1Start");
+ QTest::addColumn<int>("selection1End");
+ QTest::addColumn<int>("selection2Start");
+ QTest::addColumn<int>("selection2End");
+
+ QTest::newRow("the {<quick( bro)wn> f^ox} jumped|ltr")
+ << standard[0]
+ << 9 << 13 << 17
+ << 4 << 15
+ << 4 << 19;
+ QTest::newRow("the quick<( {bro)wn> f^ox} jumped|rtl")
+ << standard[0]
+ << 13 << 9 << 17
+ << 9 << 15
+ << 10 << 19;
+ QTest::newRow("the {<quick( bro)wn> ^}fox jumped|ltr")
+ << standard[0]
+ << 9 << 13 << 16
+ << 4 << 15
+ << 4 << 16;
+ QTest::newRow("the quick<( {bro)wn> ^}fox jumped|rtl")
+ << standard[0]
+ << 13 << 9 << 16
+ << 9 << 15
+ << 10 << 16;
+ QTest::newRow("the {<quick( bro)wn^>} fox jumped|ltr")
+ << standard[0]
+ << 9 << 13 << 15
+ << 4 << 15
+ << 4 << 15;
+ QTest::newRow("the quick<( {bro)wn^>} f^ox jumped|rtl")
+ << standard[0]
+ << 13 << 9 << 15
+ << 9 << 15
+ << 10 << 15;
+ QTest::newRow("the {<quick() ^}bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 10
+ << 4 << 15
+ << 4 << 10;
+ QTest::newRow("the quick<(^ {^bro)wn>} fox|rtl")
+ << standard[0]
+ << 13 << 9 << 10
+ << 9 << 15
+ << 10 << 15;
+ QTest::newRow("the {<quick^}( bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 9
+ << 4 << 15
+ << 4 << 9;
+ QTest::newRow("the quick{<(^ bro)wn>} fox|rtl")
+ << standard[0]
+ << 13 << 9 << 9
+ << 9 << 15
+ << 9 << 15;
+ QTest::newRow("the {<qui^ck}( bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 7
+ << 4 << 15
+ << 4 << 9;
+ QTest::newRow("the {<qui^ck}( bro)wn> fox|rtl")
+ << standard[0]
+ << 13 << 9 << 7
+ << 9 << 15
+ << 4 << 15;
+ QTest::newRow("the {<^quick}( bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 4
+ << 4 << 15
+ << 4 << 9;
+ QTest::newRow("the {<^quick}( bro)wn> fox|rtl")
+ << standard[0]
+ << 13 << 9 << 4
+ << 9 << 15
+ << 4 << 15;
+ QTest::newRow("the{^ <quick}( bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 3
+ << 4 << 15
+ << 3 << 9;
+ QTest::newRow("the{^ <quick}( bro)wn> fox|rtl")
+ << standard[0]
+ << 13 << 9 << 3
+ << 9 << 15
+ << 3 << 15;
+ QTest::newRow("{t^he <quick}( bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 1
+ << 4 << 15
+ << 0 << 9;
+ QTest::newRow("{t^he <quick}( bro)wn> fox|rtl")
+ << standard[0]
+ << 13 << 9 << 1
+ << 9 << 15
+ << 0 << 15;
+
+ QTest::newRow("{<He(ll)o>, w^orld}!|ltr")
+ << standard[2]
+ << 2 << 4 << 8
+ << 0 << 5
+ << 0 << 12;
+ QTest::newRow("{<He(ll)o>, w^orld}!|rtl")
+ << standard[2]
+ << 4 << 2 << 8
+ << 0 << 5
+ << 0 << 12;
+
+ QTest::newRow("!{dlro^w ,<o(ll)eH>}|ltr")
+ << standard[3]
+ << 9 << 11 << 5
+ << 8 << 13
+ << 1 << 13;
+ QTest::newRow("!{dlro^w ,<o(ll)eH>}|rtl")
+ << standard[3]
+ << 11 << 9 << 5
+ << 8 << 13
+ << 1 << 13;
+}
+
+void tst_qsgtextedit::moveCursorSelectionSequence()
+{
+ QFETCH(QString, testStr);
+ QFETCH(int, cursorPosition);
+ QFETCH(int, movePosition1);
+ QFETCH(int, movePosition2);
+ QFETCH(int, selection1Start);
+ QFETCH(int, selection1End);
+ QFETCH(int, selection2Start);
+ QFETCH(int, selection2End);
+
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \""+ testStr +"\"; }";
+ QDeclarativeComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *texteditObject = qobject_cast<QSGTextEdit*>(texteditComponent.create());
+ QVERIFY(texteditObject != 0);
+
+ texteditObject->setCursorPosition(cursorPosition);
+
+ texteditObject->moveCursorSelection(movePosition1, QSGTextEdit::SelectWords);
+ QCOMPARE(texteditObject->selectedText(), testStr.mid(selection1Start, selection1End - selection1Start));
+ QCOMPARE(texteditObject->selectionStart(), selection1Start);
+ QCOMPARE(texteditObject->selectionEnd(), selection1End);
+
+ texteditObject->moveCursorSelection(movePosition2, QSGTextEdit::SelectWords);
+ QCOMPARE(texteditObject->selectedText(), testStr.mid(selection2Start, selection2End - selection2Start));
+ QCOMPARE(texteditObject->selectionStart(), selection2Start);
+ QCOMPARE(texteditObject->selectionEnd(), selection2End);
+}
+
+
+void tst_qsgtextedit::mouseSelection_data()
+{
+ QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<bool>("expectSelection");
+
+ // import installed
+ QTest::newRow("on") << SRCDIR "/data/mouseselection_true.qml" << true;
+ QTest::newRow("off") << SRCDIR "/data/mouseselection_false.qml" << false;
+ QTest::newRow("default") << SRCDIR "/data/mouseselection_default.qml" << false;
+ QTest::newRow("on word selection") << SRCDIR "/data/mouseselection_true_words.qml" << true;
+ QTest::newRow("off word selection") << SRCDIR "/data/mouseselection_false_words.qml" << false;
+}
+
+void tst_qsgtextedit::mouseSelection()
+{
+ QFETCH(QString, qmlfile);
+ QFETCH(bool, expectSelection);
+
+ QSGView canvas(QUrl::fromLocalFile(qmlfile));
+
+ canvas.show();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+
+ QVERIFY(canvas.rootObject() != 0);
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit *>(canvas.rootObject());
+ QVERIFY(textEditObject != 0);
+
+ // press-and-drag-and-release from x1 to x2
+ int x1 = 10;
+ int x2 = 70;
+ int y = textEditObject->height()/2;
+ QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
+ //QTest::mouseMove(canvas, QPoint(x2,y)); // doesn't work
+ QMouseEvent mv(QEvent::MouseMove, QPoint(x2,y), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&canvas, &mv);
+ QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
+ QString str = textEditObject->selectedText();
+ if (expectSelection)
+ QVERIFY(str.length() > 3); // don't reallly care *what* was selected (and it's too sensitive to platform)
+ else
+ QVERIFY(str.isEmpty());
+}
+
+void tst_qsgtextedit::dragMouseSelection()
+{
+ QString qmlfile = SRCDIR "/data/mouseselection_true.qml";
+
+ QSGView canvas(QUrl::fromLocalFile(qmlfile));
+
+ canvas.show();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+
+ QVERIFY(canvas.rootObject() != 0);
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit *>(canvas.rootObject());
+ QVERIFY(textEditObject != 0);
+
+ // press-and-drag-and-release from x1 to x2
+ int x1 = 10;
+ int x2 = 70;
+ int y = textEditObject->height()/2;
+ QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(x2,y), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&canvas, &mv);
+ }
+ QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
+ QString str1 = textEditObject->selectedText();
+ QVERIFY(str1.length() > 3);
+
+ // press and drag the current selection.
+ x1 = 40;
+ x2 = 100;
+ QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(x2,y), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&canvas, &mv);
+ }
+ QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
+ QString str2 = textEditObject->selectedText();
+ QVERIFY(str2.length() > 3);
+
+ QVERIFY(str1 != str2); // Verify the second press and drag is a new selection and not the first moved.
+}
+
+void tst_qsgtextedit::mouseSelectionMode_data()
+{
+ QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<bool>("selectWords");
+
+ // import installed
+ QTest::newRow("SelectWords") << SRCDIR "/data/mouseselectionmode_words.qml" << true;
+ QTest::newRow("SelectCharacters") << SRCDIR "/data/mouseselectionmode_characters.qml" << false;
+ QTest::newRow("default") << SRCDIR "/data/mouseselectionmode_default.qml" << false;
+}
+
+void tst_qsgtextedit::mouseSelectionMode()
+{
+ QFETCH(QString, qmlfile);
+ QFETCH(bool, selectWords);
+
+ QString text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ QSGView canvas(QUrl::fromLocalFile(qmlfile));
+
+ canvas.show();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+
+ QVERIFY(canvas.rootObject() != 0);
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit *>(canvas.rootObject());
+ QVERIFY(textEditObject != 0);
+
+ // press-and-drag-and-release from x1 to x2
+ int x1 = 10;
+ int x2 = 70;
+ int y = textEditObject->height()/2;
+ QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
+ //QTest::mouseMove(canvas, QPoint(x2,y)); // doesn't work
+ QMouseEvent mv(QEvent::MouseMove, QPoint(x2,y), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&canvas, &mv);
+ QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
+ QString str = textEditObject->selectedText();
+ if (selectWords) {
+ QCOMPARE(str, text);
+ } else {
+ QVERIFY(str.length() > 3);
+ QVERIFY(str != text);
+ }
+}
+
+void tst_qsgtextedit::inputMethodHints()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/inputmethodhints.qml"));
+ canvas.show();
+ canvas.setFocus();
+
+ QVERIFY(canvas.rootObject() != 0);
+ QSGTextEdit *textEditObject = qobject_cast<QSGTextEdit *>(canvas.rootObject());
+ QVERIFY(textEditObject != 0);
+ QVERIFY(textEditObject->inputMethodHints() & Qt::ImhNoPredictiveText);
+ textEditObject->setInputMethodHints(Qt::ImhUppercaseOnly);
+ QVERIFY(textEditObject->inputMethodHints() & Qt::ImhUppercaseOnly);
+}
+
+void tst_qsgtextedit::positionAt()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/positionAt.qml"));
+ QVERIFY(canvas.rootObject() != 0);
+ canvas.show();
+ canvas.setFocus();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+
+ QSGTextEdit *texteditObject = qobject_cast<QSGTextEdit *>(canvas.rootObject());
+ QVERIFY(texteditObject != 0);
+
+ QFontMetrics fm(texteditObject->font());
+ const int y0 = fm.height() / 2;
+ const int y1 = fm.height() * 3 / 2;
+
+ int pos = texteditObject->positionAt(texteditObject->width()/2, y0);
+ int diff = abs(int(fm.width(texteditObject->text().left(pos))-texteditObject->width()/2));
+
+ // some tollerance for different fonts.
+#ifdef Q_OS_LINUX
+ QVERIFY(diff < 2);
+#else
+ QVERIFY(diff < 5);
+#endif
+
+ const qreal x0 = texteditObject->positionToRectangle(pos).x();
+ const qreal x1 = texteditObject->positionToRectangle(pos + 1).x();
+
+ QString preeditText = texteditObject->text().mid(0, pos);
+ texteditObject->setText(texteditObject->text().mid(pos));
+ texteditObject->setCursorPosition(0);
+
+ QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>());
+ QApplication::sendEvent(&canvas, &inputEvent);
+
+ // Check all points within the preedit text return the same position.
+ QCOMPARE(texteditObject->positionAt(0, y0), 0);
+ QCOMPARE(texteditObject->positionAt(x0 / 2, y0), 0);
+ QCOMPARE(texteditObject->positionAt(x0, y0), 0);
+
+ // Verify positioning returns to normal after the preedit text.
+ QCOMPARE(texteditObject->positionAt(x1, y0), 1);
+ QCOMPARE(texteditObject->positionToRectangle(1).x(), x1);
+
+ QVERIFY(texteditObject->positionAt(x0 / 2, y1) > 0);
+}
+
+void tst_qsgtextedit::cursorDelegate()
+{
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/cursorTest.qml"));
+ view.show();
+ view.setFocus();
+ QSGTextEdit *textEditObject = view.rootObject()->findChild<QSGTextEdit*>("textEditObject");
+ QVERIFY(textEditObject != 0);
+ QVERIFY(textEditObject->findChild<QSGItem*>("cursorInstance"));
+ //Test Delegate gets created
+ textEditObject->setFocus(true);
+ QSGItem* delegateObject = textEditObject->findChild<QSGItem*>("cursorInstance");
+ QVERIFY(delegateObject);
+ //Test Delegate gets moved
+ for(int i=0; i<= textEditObject->text().length(); i++){
+ textEditObject->setCursorPosition(i);
+ QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
+ QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
+ }
+ textEditObject->setCursorPosition(0);
+ QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x()));
+ QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y()));
+ //Test Delegate gets deleted
+ textEditObject->setCursorDelegate(0);
+ QVERIFY(!textEditObject->findChild<QSGItem*>("cursorInstance"));
+}
+
+void tst_qsgtextedit::cursorVisible()
+{
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/cursorVisible.qml"));
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ view.setFocus();
+
+ QSGTextEdit edit;
+ QSignalSpy spy(&edit, SIGNAL(cursorVisibleChanged(bool)));
+
+ QCOMPARE(edit.isCursorVisible(), false);
+
+ edit.setCursorVisible(true);
+ QCOMPARE(edit.isCursorVisible(), true);
+ QCOMPARE(spy.count(), 1);
+
+ edit.setCursorVisible(false);
+ QCOMPARE(edit.isCursorVisible(), false);
+ QCOMPARE(spy.count(), 2);
+
+ edit.setFocus(true);
+ QCOMPARE(edit.isCursorVisible(), false);
+ QCOMPARE(spy.count(), 2);
+
+ edit.setParentItem(view.rootObject());
+ QCOMPARE(edit.isCursorVisible(), true);
+ QCOMPARE(spy.count(), 3);
+
+ edit.setFocus(false);
+ QCOMPARE(edit.isCursorVisible(), false);
+ QCOMPARE(spy.count(), 4);
+
+ edit.setFocus(true);
+ QCOMPARE(edit.isCursorVisible(), true);
+ QCOMPARE(spy.count(), 5);
+
+ view.clearFocus();
+ QCOMPARE(edit.isCursorVisible(), false);
+ QCOMPARE(spy.count(), 6);
+
+ view.setFocus();
+ QCOMPARE(edit.isCursorVisible(), true);
+ QCOMPARE(spy.count(), 7);
+
+ // on mac, setActiveWindow(0) on mac does not deactivate the current application
+ // (you have to switch to a different app or hide the current app to trigger this)
+#if !defined(Q_WS_MAC)
+ QApplication::setActiveWindow(0);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(0));
+ QCOMPARE(edit.isCursorVisible(), false);
+ QCOMPARE(spy.count(), 8);
+
+ QApplication::setActiveWindow(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QCOMPARE(edit.isCursorVisible(), true);
+ QCOMPARE(spy.count(), 9);
+#endif
+}
+
+void tst_qsgtextedit::delegateLoading_data()
+{
+ QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<QString>("error");
+
+ // import installed
+ QTest::newRow("pass") << "cursorHttpTestPass.qml" << "";
+ QTest::newRow("fail1") << "cursorHttpTestFail1.qml" << "http://localhost:42332/FailItem.qml: Remote host closed the connection ";
+ QTest::newRow("fail2") << "cursorHttpTestFail2.qml" << "http://localhost:42332/ErrItem.qml:4:5: Fungus is not a type ";
+}
+
+void tst_qsgtextedit::delegateLoading()
+{
+ QFETCH(QString, qmlfile);
+ QFETCH(QString, error);
+
+ TestHTTPServer server(42332);
+ server.serveDirectory(SRCDIR "/data/httpfail", TestHTTPServer::Disconnect);
+ server.serveDirectory(SRCDIR "/data/httpslow", TestHTTPServer::Delay);
+ server.serveDirectory(SRCDIR "/data/http");
+
+ QSGView view(QUrl(QLatin1String("http://localhost:42332/") + qmlfile));
+ view.show();
+ view.setFocus();
+
+ if (!error.isEmpty()) {
+ QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
+ QTRY_VERIFY(view.status()==QSGView::Error);
+ QTRY_VERIFY(!view.rootObject()); // there is fail item inside this test
+ } else {
+ QTRY_VERIFY(view.rootObject());//Wait for loading to finish.
+ QSGTextEdit *textEditObject = view.rootObject()->findChild<QSGTextEdit*>("textEditObject");
+ // view.rootObject()->dumpObjectTree();
+ QVERIFY(textEditObject != 0);
+ textEditObject->setFocus(true);
+ QSGItem *delegate;
+ delegate = view.rootObject()->findChild<QSGItem*>("delegateOkay");
+ QVERIFY(delegate);
+ delegate = view.rootObject()->findChild<QSGItem*>("delegateSlow");
+ QVERIFY(delegate);
+
+ delete delegate;
+ }
+
+
+ //A test should be added here with a component which is ready but component.create() returns null
+ //Not sure how to accomplish this with QSGTextEdits cursor delegate
+ //###This was only needed for code coverage, and could be a case of overzealous defensive programming
+ //delegate = view.rootObject()->findChild<QSGItem*>("delegateErrorB");
+ //QVERIFY(!delegate);
+}
+
+/*
+TextEdit element should only handle left/right keys until the cursor reaches
+the extent of the text, then they should ignore the keys.
+*/
+void tst_qsgtextedit::navigation()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/navigation.qml"));
+ canvas.show();
+ canvas.setFocus();
+
+ QVERIFY(canvas.rootObject() != 0);
+
+ QSGItem *input = qobject_cast<QSGItem *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
+
+ QVERIFY(input != 0);
+ QTRY_VERIFY(input->hasActiveFocus() == true);
+ simulateKey(&canvas, Qt::Key_Left);
+ QVERIFY(input->hasActiveFocus() == false);
+ simulateKey(&canvas, Qt::Key_Right);
+ QVERIFY(input->hasActiveFocus() == true);
+ simulateKey(&canvas, Qt::Key_Right);
+ QVERIFY(input->hasActiveFocus() == true);
+ simulateKey(&canvas, Qt::Key_Right);
+ QVERIFY(input->hasActiveFocus() == false);
+ simulateKey(&canvas, Qt::Key_Left);
+ QVERIFY(input->hasActiveFocus() == true);
+}
+
+void tst_qsgtextedit::copyAndPaste() {
+#ifndef QT_NO_CLIPBOARD
+
+#ifdef Q_WS_MAC
+ {
+ PasteboardRef pasteboard;
+ OSStatus status = PasteboardCreate(0, &pasteboard);
+ if (status == noErr)
+ CFRelease(pasteboard);
+ else
+ QSKIP("This machine doesn't support the clipboard", SkipAll);
+ }
+#endif
+
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
+ QDeclarativeComponent textEditComponent(&engine);
+ textEditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEdit = qobject_cast<QSGTextEdit*>(textEditComponent.create());
+ QVERIFY(textEdit != 0);
+
+ // copy and paste
+ QCOMPARE(textEdit->text().length(), 12);
+ textEdit->select(0, textEdit->text().length());;
+ textEdit->copy();
+ QCOMPARE(textEdit->selectedText(), QString("Hello world!"));
+ QCOMPARE(textEdit->selectedText().length(), 12);
+ textEdit->setCursorPosition(0);
+ QVERIFY(textEdit->canPaste());
+ textEdit->paste();
+ QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
+ QCOMPARE(textEdit->text().length(), 24);
+
+ // canPaste
+ QVERIFY(textEdit->canPaste());
+ textEdit->setReadOnly(true);
+ QVERIFY(!textEdit->canPaste());
+ textEdit->setReadOnly(false);
+ QVERIFY(textEdit->canPaste());
+
+ // QTBUG-12339
+ // test that document and internal text attribute are in sync
+ QSGItemPrivate* pri = QSGItemPrivate::get(textEdit);
+ QSGTextEditPrivate *editPrivate = static_cast<QSGTextEditPrivate*>(pri);
+ QCOMPARE(textEdit->text(), editPrivate->text);
+
+ // select word
+ textEdit->setCursorPosition(0);
+ textEdit->selectWord();
+ QCOMPARE(textEdit->selectedText(), QString("Hello"));
+
+ // select all and cut
+ textEdit->selectAll();
+ textEdit->cut();
+ QCOMPARE(textEdit->text().length(), 0);
+ textEdit->paste();
+ QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
+ QCOMPARE(textEdit->text().length(), 24);
+#endif
+}
+
+void tst_qsgtextedit::canPaste() {
+#ifndef QT_NO_CLIPBOARD
+
+ QApplication::clipboard()->setText("Some text");
+
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
+ QDeclarativeComponent textEditComponent(&engine);
+ textEditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEdit = qobject_cast<QSGTextEdit*>(textEditComponent.create());
+ QVERIFY(textEdit != 0);
+
+ // check initial value - QTBUG-17765
+ QTextControl tc;
+ QCOMPARE(textEdit->canPaste(), tc.canPaste());
+
+#endif
+}
+
+void tst_qsgtextedit::canPasteEmpty() {
+#ifndef QT_NO_CLIPBOARD
+
+ QApplication::clipboard()->clear();
+
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"Hello world!\" }";
+ QDeclarativeComponent textEditComponent(&engine);
+ textEditComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextEdit *textEdit = qobject_cast<QSGTextEdit*>(textEditComponent.create());
+ QVERIFY(textEdit != 0);
+
+ // check initial value - QTBUG-17765
+ QTextControl tc;
+ QCOMPARE(textEdit->canPaste(), tc.canPaste());
+
+#endif
+}
+
+void tst_qsgtextedit::readOnly()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/readOnly.qml"));
+ canvas.show();
+ canvas.setFocus();
+
+ QVERIFY(canvas.rootObject() != 0);
+
+ QSGTextEdit *edit = qobject_cast<QSGTextEdit *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
+
+ QVERIFY(edit != 0);
+ QTRY_VERIFY(edit->hasActiveFocus() == true);
+ QVERIFY(edit->isReadOnly() == true);
+ QString initial = edit->text();
+ for(int k=Qt::Key_0; k<=Qt::Key_Z; k++)
+ simulateKey(&canvas, k);
+ simulateKey(&canvas, Qt::Key_Return);
+ simulateKey(&canvas, Qt::Key_Space);
+ simulateKey(&canvas, Qt::Key_Escape);
+ QCOMPARE(edit->text(), initial);
+}
+
+void tst_qsgtextedit::simulateKey(QSGView *view, int key, Qt::KeyboardModifiers modifiers)
+{
+ QKeyEvent press(QKeyEvent::KeyPress, key, modifiers);
+ QKeyEvent release(QKeyEvent::KeyRelease, key, modifiers);
+
+ QApplication::sendEvent(view, &press);
+ QApplication::sendEvent(view, &release);
+}
+
+class MyInputContext : public QInputContext
+{
+public:
+ MyInputContext() : openInputPanelReceived(false), closeInputPanelReceived(false), updateReceived(false), eventType(QEvent::None) {}
+ ~MyInputContext() {}
+
+ QString identifierName() { return QString(); }
+ QString language() { return QString(); }
+
+ void reset() {}
+
+ bool isComposing() const { return false; }
+
+ bool filterEvent( const QEvent *event )
+ {
+ if (event->type() == QEvent::RequestSoftwareInputPanel)
+ openInputPanelReceived = true;
+ if (event->type() == QEvent::CloseSoftwareInputPanel)
+ closeInputPanelReceived = true;
+ return QInputContext::filterEvent(event);
+ }
+
+ void update() { updateReceived = true; }
+
+ void sendPreeditText(const QString &text, int cursor)
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes.append(QInputMethodEvent::Attribute(
+ QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
+
+ QInputMethodEvent event(text, attributes);
+ sendEvent(event);
+ }
+
+ void mouseHandler(int x, QMouseEvent *event)
+ {
+ cursor = x;
+ eventType = event->type();
+ eventPosition = event->pos();
+ eventGlobalPosition = event->globalPos();
+ eventButton = event->button();
+ eventButtons = event->buttons();
+ eventModifiers = event->modifiers();
+ }
+
+ bool openInputPanelReceived;
+ bool closeInputPanelReceived;
+ bool updateReceived;
+ int cursor;
+ QEvent::Type eventType;
+ QPoint eventPosition;
+ QPoint eventGlobalPosition;
+ Qt::MouseButton eventButton;
+ Qt::MouseButtons eventButtons;
+ Qt::KeyboardModifiers eventModifiers;
+};
+
+void tst_qsgtextedit::textInput()
+{
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/inputMethodEvent.qml"));
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QSGTextEdit *edit = qobject_cast<QSGTextEdit *>(view.rootObject());
+ QVERIFY(edit);
+ QVERIFY(edit->hasActiveFocus() == true);
+
+ // test that input method event is committed
+ QInputMethodEvent event;
+ event.setCommitString( "Hello world!", 0, 0);
+ QApplication::sendEvent(&view, &event);
+ QCOMPARE(edit->text(), QString("Hello world!"));
+
+ // QTBUG-12339
+ // test that document and internal text attribute are in sync
+ QSGTextEditPrivate *editPrivate = static_cast<QSGTextEditPrivate*>(QSGItemPrivate::get(edit));
+ QCOMPARE(editPrivate->text, QString("Hello world!"));
+}
+
+void tst_qsgtextedit::openInputPanelOnClick()
+{
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/openInputPanel.qml"));
+ MyInputContext ic;
+ // QSGCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has focus
+ // and QWidget won't allow an input context to be set when the flag is not set.
+ view.setAttribute(Qt::WA_InputMethodEnabled, true);
+ view.setInputContext(&ic);
+ view.setAttribute(Qt::WA_InputMethodEnabled, false);
+ view.show();
+
+ qApp->setAutoSipEnabled(true);
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+
+ QSGTextEdit *edit = qobject_cast<QSGTextEdit *>(view.rootObject());
+ QVERIFY(edit);
+ QSignalSpy focusOnPressSpy(edit, SIGNAL(activeFocusOnPressChanged(bool)));
+
+ QSGItemPrivate* pri = QSGItemPrivate::get(edit);
+ QSGTextEditPrivate *editPrivate = static_cast<QSGTextEditPrivate*>(pri);
+
+ // input panel on click
+ editPrivate->showInputPanelOnFocus = false;
+
+ QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel(
+ view.style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
+ QTest::mouseClick(&view, Qt::LeftButton, 0, edit->mapToScene(QPointF(0,0)).toPoint());
+ QApplication::processEvents();
+ if (behavior == QStyle::RSIP_OnMouseClickAndAlreadyFocused) {
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QTest::mouseClick(&view, Qt::LeftButton, 0, edit->mapToScene(QPointF(0,0)).toPoint());
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, true);
+ } else if (behavior == QStyle::RSIP_OnMouseClick) {
+ QCOMPARE(ic.openInputPanelReceived, true);
+ }
+ ic.openInputPanelReceived = false;
+
+ // focus should not cause input panels to open or close
+ edit->setFocus(false);
+ edit->setFocus(true);
+ edit->setFocus(false);
+ edit->setFocus(true);
+ edit->setFocus(false);
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QCOMPARE(ic.closeInputPanelReceived, false);
+}
+
+void tst_qsgtextedit::openInputPanelOnFocus()
+{
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/openInputPanel.qml"));
+ MyInputContext ic;
+ // QSGCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has focus
+ // and QWidget won't allow an input context to be set when the flag is not set.
+ view.setAttribute(Qt::WA_InputMethodEnabled, true);
+ view.setInputContext(&ic);
+ view.setAttribute(Qt::WA_InputMethodEnabled, false);
+ view.show();
+
+ qApp->setAutoSipEnabled(true);
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+
+ QSGTextEdit *edit = qobject_cast<QSGTextEdit *>(view.rootObject());
+ QVERIFY(edit);
+ QSignalSpy focusOnPressSpy(edit, SIGNAL(activeFocusOnPressChanged(bool)));
+
+ QSGItemPrivate* pri = QSGItemPrivate::get(edit);
+ QSGTextEditPrivate *editPrivate = static_cast<QSGTextEditPrivate*>(pri);
+ editPrivate->showInputPanelOnFocus = true;
+
+ // test default values
+ QVERIFY(edit->focusOnPress());
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QCOMPARE(ic.closeInputPanelReceived, false);
+
+ // focus on press, input panel on focus
+ QTest::mousePress(&view, Qt::LeftButton, 0, edit->mapToScene(QPointF(0,0)).toPoint());
+ QApplication::processEvents();
+ QVERIFY(edit->hasActiveFocus());
+ QCOMPARE(ic.openInputPanelReceived, true);
+ ic.openInputPanelReceived = false;
+
+ // no events on release
+ QTest::mouseRelease(&view, Qt::LeftButton, 0, edit->mapToScene(QPointF(0,0)).toPoint());
+ QCOMPARE(ic.openInputPanelReceived, false);
+ ic.openInputPanelReceived = false;
+
+ // if already focused, input panel can be opened on press
+ QVERIFY(edit->hasActiveFocus());
+ QTest::mousePress(&view, Qt::LeftButton, 0, edit->mapToScene(QPointF(0,0)).toPoint());
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, true);
+ ic.openInputPanelReceived = false;
+
+ // input method should stay enabled if focus
+ // is lost to an item that also accepts inputs
+ QSGTextEdit anotherEdit;
+ anotherEdit.setParentItem(view.rootObject());
+ anotherEdit.setFocus(true);
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, true);
+ ic.openInputPanelReceived = false;
+ QCOMPARE(view.inputContext(), (QInputContext*)&ic);
+ QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // input method should be disabled if focus
+ // is lost to an item that doesn't accept inputs
+ QSGItem item;
+ item.setParentItem(view.rootObject());
+ item.setFocus(true);
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QVERIFY(view.inputContext() == 0);
+ QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // no automatic input panel events should
+ // be sent if activeFocusOnPress is false
+ edit->setFocusOnPress(false);
+ QCOMPARE(focusOnPressSpy.count(),1);
+ edit->setFocusOnPress(false);
+ QCOMPARE(focusOnPressSpy.count(),1);
+ edit->setFocus(false);
+ edit->setFocus(true);
+ QTest::mousePress(&view, Qt::LeftButton, 0, edit->mapToScene(QPointF(0,0)).toPoint());
+ QTest::mouseRelease(&view, Qt::LeftButton, 0, edit->mapToScene(QPointF(0,0)).toPoint());
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QCOMPARE(ic.closeInputPanelReceived, false);
+
+ // one show input panel event should
+ // be set when openSoftwareInputPanel is called
+ edit->openSoftwareInputPanel();
+ QCOMPARE(ic.openInputPanelReceived, true);
+ QCOMPARE(ic.closeInputPanelReceived, false);
+ ic.openInputPanelReceived = false;
+
+ // one close input panel event should
+ // be sent when closeSoftwareInputPanel is called
+ edit->closeSoftwareInputPanel();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QCOMPARE(ic.closeInputPanelReceived, true);
+ ic.closeInputPanelReceived = false;
+
+ // set activeFocusOnPress back to true
+ edit->setFocusOnPress(true);
+ QCOMPARE(focusOnPressSpy.count(),2);
+ edit->setFocusOnPress(true);
+ QCOMPARE(focusOnPressSpy.count(),2);
+ edit->setFocus(false);
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QCOMPARE(ic.closeInputPanelReceived, false);
+ ic.closeInputPanelReceived = false;
+
+ // input panel should not re-open
+ // if focus has already been set
+ edit->setFocus(true);
+ QCOMPARE(ic.openInputPanelReceived, true);
+ ic.openInputPanelReceived = false;
+ edit->setFocus(true);
+ QCOMPARE(ic.openInputPanelReceived, false);
+
+ // input method should be disabled
+ // if TextEdit loses focus
+ edit->setFocus(false);
+ QApplication::processEvents();
+ QVERIFY(view.inputContext() == 0);
+ QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // input method should not be enabled
+ // if TextEdit is read only.
+ edit->setReadOnly(true);
+ ic.openInputPanelReceived = false;
+ edit->setFocus(true);
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QVERIFY(view.inputContext() == 0);
+ QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
+}
+
+void tst_qsgtextedit::geometrySignals()
+{
+ QDeclarativeComponent component(&engine, SRCDIR "/data/geometrySignals.qml");
+ QObject *o = component.create();
+ QVERIFY(o);
+ QCOMPARE(o->property("bindingWidth").toInt(), 400);
+ QCOMPARE(o->property("bindingHeight").toInt(), 500);
+ delete o;
+}
+
+void tst_qsgtextedit::pastingRichText_QTBUG_14003()
+{
+#ifndef QT_NO_CLIPBOARD
+ QString componentStr = "import QtQuick 2.0\nTextEdit { textFormat: TextEdit.PlainText }";
+ QDeclarativeComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGTextEdit *obj = qobject_cast<QSGTextEdit*>(component.create());
+
+ QTRY_VERIFY(obj != 0);
+ QTRY_VERIFY(obj->textFormat() == QSGTextEdit::PlainText);
+
+ QMimeData *mData = new QMimeData;
+ mData->setHtml("<font color=\"red\">Hello</font>");
+ QApplication::clipboard()->setMimeData(mData);
+
+ obj->paste();
+ QTRY_VERIFY(obj->text() == "");
+ QTRY_VERIFY(obj->textFormat() == QSGTextEdit::PlainText);
+#endif
+}
+
+void tst_qsgtextedit::implicitSize_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QString>("wrap");
+ QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "TextEdit.NoWrap";
+ QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "TextEdit.NoWrap";
+ QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "TextEdit.Wrap";
+ QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "TextEdit.Wrap";
+}
+
+void tst_qsgtextedit::implicitSize()
+{
+ QFETCH(QString, text);
+ QFETCH(QString, wrap);
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \"" + text + "\"; width: 50; wrapMode: " + wrap + " }";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGTextEdit *textObject = qobject_cast<QSGTextEdit*>(textComponent.create());
+
+ QVERIFY(textObject->width() < textObject->implicitWidth());
+ QVERIFY(textObject->height() == textObject->implicitHeight());
+
+ textObject->resetWidth();
+ QVERIFY(textObject->width() == textObject->implicitWidth());
+ QVERIFY(textObject->height() == textObject->implicitHeight());
+}
+
+void tst_qsgtextedit::testQtQuick11Attributes()
+{
+ QFETCH(QString, code);
+ QFETCH(QString, warning);
+ QFETCH(QString, error);
+
+ QDeclarativeEngine engine;
+ QObject *obj;
+
+ QDeclarativeComponent valid(&engine);
+ valid.setData("import QtQuick 2.0; TextEdit { " + code.toUtf8() + " }", QUrl(""));
+ obj = valid.create();
+ QVERIFY(obj);
+ QVERIFY(valid.errorString().isEmpty());
+ delete obj;
+
+ QDeclarativeComponent invalid(&engine);
+ invalid.setData("import QtQuick 1.0; TextEdit { " + code.toUtf8() + " }", QUrl(""));
+ QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
+ obj = invalid.create();
+ QCOMPARE(invalid.errorString(), error);
+ delete obj;
+}
+
+void tst_qsgtextedit::testQtQuick11Attributes_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("canPaste") << "property bool foo: canPaste"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: canPaste"
+ << "";
+
+ QTest::newRow("lineCount") << "property int foo: lineCount"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: lineCount"
+ << "";
+
+ QTest::newRow("moveCursorSelection") << "Component.onCompleted: moveCursorSelection(0, TextEdit.SelectCharacters)"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: moveCursorSelection"
+ << "";
+
+ QTest::newRow("deselect") << "Component.onCompleted: deselect()"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: deselect"
+ << "";
+
+ QTest::newRow("onLinkActivated") << "onLinkActivated: {}"
+ << "QDeclarativeComponent: Component is not ready"
+ << ":1 \"TextEdit.onLinkActivated\" is not available in QtQuick 1.0.\n";
+}
+
+void tst_qsgtextedit::preeditMicroFocus()
+{
+ QString preeditText = "super";
+
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/inputMethodEvent.qml"));
+ MyInputContext ic;
+ view.setInputContext(&ic);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QSGTextEdit *edit = qobject_cast<QSGTextEdit *>(view.rootObject());
+ QVERIFY(edit);
+
+ QRect currentRect;
+ QRect previousRect = edit->inputMethodQuery(Qt::ImMicroFocus).toRect();
+
+ // Verify that the micro focus rect is positioned the same for position 0 as
+ // it would be if there was no preedit text.
+ ic.updateReceived = false;
+ ic.sendPreeditText(preeditText, 0);
+ currentRect = edit->inputMethodQuery(Qt::ImMicroFocus).toRect();
+ QCOMPARE(currentRect, previousRect);
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+ QCOMPARE(ic.updateReceived, true);
+#endif
+
+ // Verify that the micro focus rect moves to the left as the cursor position
+ // is incremented.
+ for (int i = 1; i <= 5; ++i) {
+ ic.updateReceived = false;
+ ic.sendPreeditText(preeditText, i);
+ currentRect = edit->inputMethodQuery(Qt::ImMicroFocus).toRect();
+ QVERIFY(previousRect.left() < currentRect.left());
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+ QCOMPARE(ic.updateReceived, true);
+#endif
+ previousRect = currentRect;
+ }
+
+ // Verify that if there is no preedit cursor then the micro focus rect is the
+ // same as it would be if it were positioned at the end of the preedit text.
+ ic.sendPreeditText(preeditText, 0);
+ ic.updateReceived = false;
+ ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>()));
+ currentRect = edit->inputMethodQuery(Qt::ImMicroFocus).toRect();
+ QCOMPARE(currentRect, previousRect);
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+ QCOMPARE(ic.updateReceived, true);
+#endif
+}
+
+void tst_qsgtextedit::inputContextMouseHandler()
+{
+ QString text = "supercalifragisiticexpialidocious!";
+
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/inputContext.qml"));
+ MyInputContext ic;
+ view.setInputContext(&ic);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QSGTextEdit *edit = qobject_cast<QSGTextEdit *>(view.rootObject());
+ QVERIFY(edit);
+ edit->setCursorPosition(12);
+
+ QFontMetricsF fm(edit->font());
+ const qreal y = fm.height() / 2;
+
+ QPoint position2 = edit->mapToScene(QPointF(fm.width(text.mid(0, 2)), y)).toPoint();
+ QPoint position8 = edit->mapToScene(QPointF(fm.width(text.mid(0, 8)), y)).toPoint();
+ QPoint position20 = edit->mapToScene(QPointF(fm.width(text.mid(0, 20)), y)).toPoint();
+ QPoint position27 = edit->mapToScene(QPointF(fm.width(text.mid(0, 27)), y)).toPoint();
+ QPoint globalPosition2 = view.mapToGlobal(position2);
+ QPoint globalposition8 = view.mapToGlobal(position8);
+ QPoint globalposition20 = view.mapToGlobal(position20);
+ QPoint globalposition27 = view.mapToGlobal(position27);
+
+ ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>()));
+
+ QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, position2);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
+ QCOMPARE(ic.eventPosition, position2);
+ QCOMPARE(ic.eventGlobalPosition, globalPosition2);
+ QCOMPARE(ic.eventButton, Qt::LeftButton);
+ QCOMPARE(ic.eventModifiers, Qt::NoModifier);
+ QVERIFY(ic.cursor < 0);
+ ic.eventType = QEvent::None;
+
+ QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position2);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
+ QCOMPARE(ic.eventPosition, position2);
+ QCOMPARE(ic.eventGlobalPosition, globalPosition2);
+ QCOMPARE(ic.eventButton, Qt::LeftButton);
+ QCOMPARE(ic.eventModifiers, Qt::NoModifier);
+ QVERIFY(ic.cursor < 0);
+ ic.eventType = QEvent::None;
+
+ { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&view, &mv); }
+ QCOMPARE(ic.eventType, QEvent::None);
+
+ { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&view, &mv); }
+ QCOMPARE(ic.eventType, QEvent::MouseMove);
+ QCOMPARE(ic.eventPosition, position27);
+ QCOMPARE(ic.eventGlobalPosition, globalposition27);
+ QCOMPARE(ic.eventButton, Qt::LeftButton);
+ QCOMPARE(ic.eventModifiers, Qt::NoModifier);
+ QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); // 15 is expected but some platforms may be off by one.
+ ic.eventType = QEvent::None;
+
+ QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position27);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
+ QCOMPARE(ic.eventPosition, position27);
+ QCOMPARE(ic.eventGlobalPosition, globalposition27);
+ QCOMPARE(ic.eventButton, Qt::LeftButton);
+ QCOMPARE(ic.eventModifiers, Qt::NoModifier);
+ QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
+ ic.eventType = QEvent::None;
+
+ // And in the other direction.
+ QTest::mouseDClick(&view, Qt::LeftButton, Qt::ControlModifier, position27);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
+ QCOMPARE(ic.eventPosition, position27);
+ QCOMPARE(ic.eventGlobalPosition, globalposition27);
+ QCOMPARE(ic.eventButton, Qt::LeftButton);
+ QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
+ QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
+ ic.eventType = QEvent::None;
+
+ QTest::mousePress(&view, Qt::RightButton, Qt::ControlModifier, position27);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
+ QCOMPARE(ic.eventPosition, position27);
+ QCOMPARE(ic.eventGlobalPosition, globalposition27);
+ QCOMPARE(ic.eventButton, Qt::RightButton);
+ QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
+ QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
+ ic.eventType = QEvent::None;
+
+ { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
+ QApplication::sendEvent(&view, &mv); }
+ QCOMPARE(ic.eventType, QEvent::MouseMove);
+ QCOMPARE(ic.eventPosition, position20);
+ QCOMPARE(ic.eventGlobalPosition, globalposition20);
+ QCOMPARE(ic.eventButton, Qt::RightButton);
+ QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
+ QVERIFY(ic.cursor >= 7 && ic.cursor <= 9);
+ ic.eventType = QEvent::None;
+
+ { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
+ QApplication::sendEvent(&view, &mv); }
+ QCOMPARE(ic.eventType, QEvent::None);
+
+ QTest::mouseRelease(&view, Qt::RightButton, Qt::ControlModifier, position2);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
+ QCOMPARE(ic.eventPosition, position2);
+ QCOMPARE(ic.eventGlobalPosition, globalPosition2);
+ QCOMPARE(ic.eventButton, Qt::RightButton);
+ QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
+ QVERIFY(ic.cursor < 0);
+ ic.eventType = QEvent::None;
+}
+
+void tst_qsgtextedit::inputMethodComposing()
+{
+ QString text = "supercalifragisiticexpialidocious!";
+
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/inputContext.qml"));
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QSGTextEdit *edit = qobject_cast<QSGTextEdit *>(view.rootObject());
+ QVERIFY(edit);
+ QSignalSpy spy(edit, SIGNAL(inputMethodComposingChanged()));
+ edit->setCursorPosition(12);
+
+ QCOMPARE(edit->isInputMethodComposing(), false);
+
+ {
+ QInputMethodEvent event(text.mid(3), QList<QInputMethodEvent::Attribute>());
+ QApplication::sendEvent(&view, &event);
+ }
+ QCOMPARE(edit->isInputMethodComposing(), true);
+ QCOMPARE(spy.count(), 1);
+
+ {
+ QInputMethodEvent event(text.mid(12), QList<QInputMethodEvent::Attribute>());
+ QApplication::sendEvent(&view, &event);
+ }
+ QCOMPARE(spy.count(), 1);
+
+ {
+ QInputMethodEvent event;
+ QApplication::sendEvent(&view, &event);
+ }
+ QCOMPARE(edit->isInputMethodComposing(), false);
+ QCOMPARE(spy.count(), 2);
+}
+
+void tst_qsgtextedit::cursorRectangleSize()
+{
+ QSGView *canvas = new QSGView(QUrl::fromLocalFile(SRCDIR "/data/CursorRect.qml"));
+ QVERIFY(canvas->rootObject() != 0);
+ canvas->show();
+ canvas->setFocus();
+ QApplication::setActiveWindow(canvas);
+ QTest::qWaitForWindowShown(canvas);
+
+ QSGTextEdit *textEdit = qobject_cast<QSGTextEdit *>(canvas->rootObject());
+ QVERIFY(textEdit != 0);
+ textEdit->setFocus(Qt::OtherFocusReason);
+ QRectF cursorRect = textEdit->positionToRectangle(textEdit->cursorPosition());
+ QRectF microFocusFromScene = canvas->inputMethodQuery(Qt::ImMicroFocus).toRectF();
+ QRectF microFocusFromApp= QApplication::focusWidget()->inputMethodQuery(Qt::ImMicroFocus).toRectF();
+
+ QCOMPARE(microFocusFromScene.size(), cursorRect.size());
+ QCOMPARE(microFocusFromApp.size(), cursorRect.size());
+
+ delete canvas;
+}
+
+QTEST_MAIN(tst_qsgtextedit)
+
+#include "tst_qsgtextedit.moc"
diff --git a/tests/auto/declarative/qsgtextinput/data/cursorTest.qml b/tests/auto/declarative/qsgtextinput/data/cursorTest.qml
new file mode 100644
index 0000000000..01858fba77
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/cursorTest.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Rectangle { width: 300; height: 300; color: "white"
+ TextInput { text: "Hello world!"; id: textInputObject; objectName: "textInputObject"
+ resources: [ Component { id:cursor; Item { id:cursorInstance; objectName: "cursorInstance";} } ]
+ cursorDelegate: cursor
+ }
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/cursorVisible.qml b/tests/auto/declarative/qsgtextinput/data/cursorVisible.qml
new file mode 100644
index 0000000000..49e9386947
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/cursorVisible.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+Item {
+ width: 100
+ height: 20
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/echoMode.qml b/tests/auto/declarative/qsgtextinput/data/echoMode.qml
new file mode 100644
index 0000000000..f8a6cf1c89
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/echoMode.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+Rectangle {
+ property QtObject myInput: input
+
+ width: 400; height: 200; color: "green"
+
+ TextInput { id: input; focus: true
+ text: "ABCDefgh"
+ }
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/geometrySignals.qml b/tests/auto/declarative/qsgtextinput/data/geometrySignals.qml
new file mode 100644
index 0000000000..90855a61cf
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/geometrySignals.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ width: 400; height: 500;
+ property int bindingWidth: text.width
+ property int bindingHeight: text.height
+
+ TextEdit {
+ id: text
+ anchors.fill: parent
+ }
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/halign_center.png b/tests/auto/declarative/qsgtextinput/data/halign_center.png
new file mode 100644
index 0000000000..53e09a8e5b
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/halign_center.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextinput/data/halign_left.png b/tests/auto/declarative/qsgtextinput/data/halign_left.png
new file mode 100644
index 0000000000..247acbc9df
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/halign_left.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextinput/data/halign_right.png b/tests/auto/declarative/qsgtextinput/data/halign_right.png
new file mode 100644
index 0000000000..691bc75c89
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/halign_right.png
Binary files differ
diff --git a/tests/auto/declarative/qsgtextinput/data/horizontalAlignment.qml b/tests/auto/declarative/qsgtextinput/data/horizontalAlignment.qml
new file mode 100644
index 0000000000..e0fef4c11e
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/horizontalAlignment.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: top
+ width: 70; height: 70;
+
+ property alias horizontalAlignment: text.horizontalAlignment
+ property string text: "Test"
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 60
+ height: 20
+ color: "green"
+
+ TextInput {
+ id: text
+ anchors.fill: parent
+ text: top.text
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/horizontalAlignment_RightToLeft.qml b/tests/auto/declarative/qsgtextinput/data/horizontalAlignment_RightToLeft.qml
new file mode 100644
index 0000000000..15fbabe28c
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/horizontalAlignment_RightToLeft.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: top
+ width: 200; height: 70;
+
+ property alias horizontalAlignment: text.horizontalAlignment
+ property string text: "اختبا"
+
+ Rectangle {
+ anchors.centerIn: parent
+ width: 180
+ height: 20
+ color: "green"
+
+ TextInput {
+ id: text
+ objectName: "text"
+ anchors.fill: parent
+ text: top.text
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/inputContext.qml b/tests/auto/declarative/qsgtextinput/data/inputContext.qml
new file mode 100644
index 0000000000..dfc80990c6
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/inputContext.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+TextInput {
+ width: 200
+ text: "supercalifra"
+ focus: true
+ cursorPosition: 12
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/inputMethodEvent.qml b/tests/auto/declarative/qsgtextinput/data/inputMethodEvent.qml
new file mode 100644
index 0000000000..f8446ab7b9
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/inputMethodEvent.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+TextInput {
+ focus: true
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/inputmethods.qml b/tests/auto/declarative/qsgtextinput/data/inputmethods.qml
new file mode 100644
index 0000000000..711e89144c
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/inputmethods.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextInput {
+ text: "Hello world!"
+ inputMethodHints: Qt.ImhNoPredictiveText
+ Keys.onLeftPressed: {}
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/masks.qml b/tests/auto/declarative/qsgtextinput/data/masks.qml
new file mode 100644
index 0000000000..589b6a3c15
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/masks.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextInput{
+ focus: true
+ objectName: "myInput"
+ inputMask: "HHHHhhhh; "
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/maxLength.qml b/tests/auto/declarative/qsgtextinput/data/maxLength.qml
new file mode 100644
index 0000000000..cca537ed6b
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/maxLength.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextInput{
+ focus: true
+ objectName: "myInput"
+ maximumLength: 10
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/mouseselection_true.qml b/tests/auto/declarative/qsgtextinput/data/mouseselection_true.qml
new file mode 100644
index 0000000000..974041b04a
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/mouseselection_true.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextInput {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: true
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/mouseselectionmode_characters.qml b/tests/auto/declarative/qsgtextinput/data/mouseselectionmode_characters.qml
new file mode 100644
index 0000000000..f7c658b618
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/mouseselectionmode_characters.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+TextInput {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: true
+ mouseSelectionMode: TextInput.SelectCharacters
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/mouseselectionmode_default.qml b/tests/auto/declarative/qsgtextinput/data/mouseselectionmode_default.qml
new file mode 100644
index 0000000000..974041b04a
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/mouseselectionmode_default.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextInput {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: true
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/mouseselectionmode_words.qml b/tests/auto/declarative/qsgtextinput/data/mouseselectionmode_words.qml
new file mode 100644
index 0000000000..20e777e470
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/mouseselectionmode_words.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+TextInput {
+ focus: true
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ selectByMouse: true
+ mouseSelectionMode: TextInput.SelectWords
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/navigation.qml b/tests/auto/declarative/qsgtextinput/data/navigation.qml
new file mode 100644
index 0000000000..3a7d07b3c7
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/navigation.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Rectangle {
+ property variant myInput: input
+
+ width: 800; height: 600; color: "blue"
+
+ Item {
+ id: firstItem;
+ KeyNavigation.right: input
+ }
+
+ TextInput { id: input; focus: true
+ text: "Needs some text"
+ KeyNavigation.left: firstItem
+ KeyNavigation.right: lastItem
+ KeyNavigation.up: firstItem
+ KeyNavigation.down: lastItem
+ }
+ Item {
+ id: lastItem
+ KeyNavigation.left: input
+ }
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/openInputPanel.qml b/tests/auto/declarative/qsgtextinput/data/openInputPanel.qml
new file mode 100644
index 0000000000..3924b2ab99
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/openInputPanel.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+TextInput {
+ text: "Hello world"
+ focus: false
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/positionAt.qml b/tests/auto/declarative/qsgtextinput/data/positionAt.qml
new file mode 100644
index 0000000000..7611376e13
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/positionAt.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+TextInput{
+ focus: true
+ objectName: "myInput"
+ width: 50
+ text: "This is a long piece of text"
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/preeditAutoScroll.qml b/tests/auto/declarative/qsgtextinput/data/preeditAutoScroll.qml
new file mode 100644
index 0000000000..9d98a2e220
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/preeditAutoScroll.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+TextInput {
+ focus: true
+ text: "super"
+ autoScroll: true
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/readOnly.qml b/tests/auto/declarative/qsgtextinput/data/readOnly.qml
new file mode 100644
index 0000000000..9cda7fbd1d
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/readOnly.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Rectangle {
+ property variant myInput: input
+
+ width: 800; height: 600; color: "blue"
+
+ TextInput { id: input; focus: true
+ readOnly: true
+ text: "I am the very model of a modern major general.\n"
+ }
+}
diff --git a/tests/auto/declarative/qsgtextinput/data/validators.qml b/tests/auto/declarative/qsgtextinput/data/validators.qml
new file mode 100644
index 0000000000..0a074ce7dc
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/data/validators.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+
+Item {
+ property variant intInput: intInput
+ property variant dblInput: dblInput
+ property variant strInput: strInput
+
+ width: 800; height: 600;
+
+ Column{
+ TextInput { id: intInput;
+ validator: IntValidator{top: 11; bottom: 2}
+ }
+ TextInput { id: dblInput;
+ validator: DoubleValidator{top: 12.12; bottom: 2.93; decimals: 2; notation: DoubleValidator.StandardNotation}
+ }
+ TextInput { id: strInput;
+ validator: RegExpValidator { regExp: /[a-zA-z]{2,4}/ }
+ }
+ }
+
+}
diff --git a/tests/auto/declarative/qsgtextinput/qsgtextinput.pro b/tests/auto/declarative/qsgtextinput/qsgtextinput.pro
new file mode 100644
index 0000000000..599c2a8e43
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/qsgtextinput.pro
@@ -0,0 +1,14 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qsgtextinput.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
diff --git a/tests/auto/declarative/qsgtextinput/tst_qsgtextinput.cpp b/tests/auto/declarative/qsgtextinput/tst_qsgtextinput.cpp
new file mode 100644
index 0000000000..b349de9800
--- /dev/null
+++ b/tests/auto/declarative/qsgtextinput/tst_qsgtextinput.cpp
@@ -0,0 +1,2471 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtTest/QSignalSpy>
+#include "../../../shared/util.h"
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QFile>
+#include <QtDeclarative/qsgview.h>
+#include <private/qsgtextinput_p.h>
+#include <private/qsgtextinput_p_p.h>
+#include <QDebug>
+#include <QDir>
+#include <QStyle>
+#include <QInputContext>
+#include <private/qapplication_p.h>
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+Q_DECLARE_METATYPE(QSGTextInput::SelectionMode)
+
+QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual)
+{
+ // XXX This will be replaced by some clever persistent platform image store.
+ QString persistent_dir = SRCDIR "/data";
+ QString arch = "unknown-architecture"; // QTest needs to help with this.
+
+ QString expectfile = persistent_dir + QDir::separator() + filebasename + "-" + arch + ".png";
+
+ if (!QFile::exists(expectfile)) {
+ actual.save(expectfile);
+ qWarning() << "created" << expectfile;
+ }
+
+ return expectfile;
+}
+
+class tst_qsgtextinput : public QObject
+
+{
+ Q_OBJECT
+public:
+ tst_qsgtextinput();
+
+private slots:
+
+ void text();
+ void width();
+ void font();
+ void color();
+ void selection();
+ void isRightToLeft_data();
+ void isRightToLeft();
+ void moveCursorSelection_data();
+ void moveCursorSelection();
+ void moveCursorSelectionSequence_data();
+ void moveCursorSelectionSequence();
+ void dragMouseSelection();
+ void mouseSelectionMode_data();
+ void mouseSelectionMode();
+
+ void horizontalAlignment_data();
+ void horizontalAlignment();
+ void horizontalAlignment_RightToLeft();
+
+ void positionAt();
+
+ void maxLength();
+ void masks();
+ void validators();
+ void inputMethods();
+
+ void passwordCharacter();
+ void cursorDelegate();
+ void cursorVisible();
+ void cursorRectangle();
+ void navigation();
+ void navigation_RTL();
+ void copyAndPaste();
+ void canPasteEmpty();
+ void canPaste();
+ void readOnly();
+
+ void openInputPanelOnClick();
+ void openInputPanelOnFocus();
+ void setHAlignClearCache();
+ void focusOutClearSelection();
+
+ void echoMode();
+ void geometrySignals();
+ void testQtQuick11Attributes();
+ void testQtQuick11Attributes_data();
+
+ void preeditAutoScroll();
+ void preeditMicroFocus();
+ void inputContextMouseHandler();
+ void inputMethodComposing();
+ void cursorRectangleSize();
+
+private:
+ void simulateKey(QSGView *, int key);
+
+ QDeclarativeEngine engine;
+ QStringList standard;
+ QStringList colorStrings;
+};
+
+tst_qsgtextinput::tst_qsgtextinput()
+{
+ standard << "the quick brown fox jumped over the lazy dog"
+ << "It's supercalifragisiticexpialidocious!"
+ << "Hello, world!"
+ << "!dlrow ,olleH"
+ << " spacey text ";
+
+ colorStrings << "aliceblue"
+ << "antiquewhite"
+ << "aqua"
+ << "darkkhaki"
+ << "darkolivegreen"
+ << "dimgray"
+ << "palevioletred"
+ << "lightsteelblue"
+ << "#000000"
+ << "#AAAAAA"
+ << "#FFFFFF"
+ << "#2AC05F";
+}
+
+void tst_qsgtextinput::text()
+{
+ {
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData("import QtQuick 2.0\nTextInput { text: \"\" }", QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->text(), QString(""));
+
+ delete textinputObject;
+ }
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextInput { text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->text(), standard.at(i));
+
+ delete textinputObject;
+ }
+
+}
+
+void tst_qsgtextinput::width()
+{
+ // uses Font metrics to find the width for standard
+ {
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData("import QtQuick 2.0\nTextInput { text: \"\" }", QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->width(), 0.0);
+
+ delete textinputObject;
+ }
+
+ for (int i = 0; i < standard.size(); i++)
+ {
+ QFont f;
+ QFontMetricsF fm(f);
+ qreal metricWidth = fm.width(standard.at(i));
+
+ QString componentStr = "import QtQuick 2.0\nTextInput { text: \"" + standard.at(i) + "\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+
+ QVERIFY(textinputObject != 0);
+ int delta = abs(int(int(textinputObject->width()) - metricWidth));
+ QVERIFY(delta <= 3.0); // As best as we can hope for cross-platform.
+
+ delete textinputObject;
+ }
+}
+
+void tst_qsgtextinput::font()
+{
+ //test size, then bold, then italic, then family
+ {
+ QString componentStr = "import QtQuick 2.0\nTextInput { font.pointSize: 40; text: \"Hello World\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->font().pointSize(), 40);
+ QCOMPARE(textinputObject->font().bold(), false);
+ QCOMPARE(textinputObject->font().italic(), false);
+
+ delete textinputObject;
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nTextInput { font.bold: true; text: \"Hello World\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->font().bold(), true);
+ QCOMPARE(textinputObject->font().italic(), false);
+
+ delete textinputObject;
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nTextInput { font.italic: true; text: \"Hello World\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->font().italic(), true);
+ QCOMPARE(textinputObject->font().bold(), false);
+
+ delete textinputObject;
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nTextInput { font.family: \"Helvetica\"; text: \"Hello World\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->font().family(), QString("Helvetica"));
+ QCOMPARE(textinputObject->font().bold(), false);
+ QCOMPARE(textinputObject->font().italic(), false);
+
+ delete textinputObject;
+ }
+
+ {
+ QString componentStr = "import QtQuick 2.0\nTextInput { font.family: \"\"; text: \"Hello World\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->font().family(), QString(""));
+
+ delete textinputObject;
+ }
+}
+
+void tst_qsgtextinput::color()
+{
+ //test color
+ for (int i = 0; i < colorStrings.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextInput { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->color(), QColor(colorStrings.at(i)));
+
+ delete textinputObject;
+ }
+
+ //test selection color
+ for (int i = 0; i < colorStrings.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextInput { selectionColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->selectionColor(), QColor(colorStrings.at(i)));
+
+ delete textinputObject;
+ }
+
+ //test selected text color
+ for (int i = 0; i < colorStrings.size(); i++)
+ {
+ QString componentStr = "import QtQuick 2.0\nTextInput { selectedTextColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->selectedTextColor(), QColor(colorStrings.at(i)));
+
+ delete textinputObject;
+ }
+
+ {
+ QString colorStr = "#AA001234";
+ QColor testColor("#001234");
+ testColor.setAlpha(170);
+
+ QString componentStr = "import QtQuick 2.0\nTextInput { color: \"" + colorStr + "\"; text: \"Hello World\" }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+
+ QVERIFY(textinputObject != 0);
+ QCOMPARE(textinputObject->color(), testColor);
+
+ delete textinputObject;
+ }
+}
+
+void tst_qsgtextinput::selection()
+{
+ QString testStr = standard[0];
+ QString componentStr = "import QtQuick 2.0\nTextInput { text: \""+ testStr +"\"; }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+ QVERIFY(textinputObject != 0);
+
+
+ //Test selection follows cursor
+ for(int i=0; i<= testStr.size(); i++) {
+ textinputObject->setCursorPosition(i);
+ QCOMPARE(textinputObject->cursorPosition(), i);
+ QCOMPARE(textinputObject->selectionStart(), i);
+ QCOMPARE(textinputObject->selectionEnd(), i);
+ QVERIFY(textinputObject->selectedText().isNull());
+ }
+
+ textinputObject->setCursorPosition(0);
+ QVERIFY(textinputObject->cursorPosition() == 0);
+ QVERIFY(textinputObject->selectionStart() == 0);
+ QVERIFY(textinputObject->selectionEnd() == 0);
+ QVERIFY(textinputObject->selectedText().isNull());
+
+ // Verify invalid positions are ignored.
+ textinputObject->setCursorPosition(-1);
+ QVERIFY(textinputObject->cursorPosition() == 0);
+ QVERIFY(textinputObject->selectionStart() == 0);
+ QVERIFY(textinputObject->selectionEnd() == 0);
+ QVERIFY(textinputObject->selectedText().isNull());
+
+ textinputObject->setCursorPosition(textinputObject->text().count()+1);
+ QVERIFY(textinputObject->cursorPosition() == 0);
+ QVERIFY(textinputObject->selectionStart() == 0);
+ QVERIFY(textinputObject->selectionEnd() == 0);
+ QVERIFY(textinputObject->selectedText().isNull());
+
+ //Test selection
+ for(int i=0; i<= testStr.size(); i++) {
+ textinputObject->select(0,i);
+ QCOMPARE(testStr.mid(0,i), textinputObject->selectedText());
+ }
+ for(int i=0; i<= testStr.size(); i++) {
+ textinputObject->select(i,testStr.size());
+ QCOMPARE(testStr.mid(i,testStr.size()-i), textinputObject->selectedText());
+ }
+
+ textinputObject->setCursorPosition(0);
+ QVERIFY(textinputObject->cursorPosition() == 0);
+ QVERIFY(textinputObject->selectionStart() == 0);
+ QVERIFY(textinputObject->selectionEnd() == 0);
+ QVERIFY(textinputObject->selectedText().isNull());
+
+ //Test Error Ignoring behaviour
+ textinputObject->setCursorPosition(0);
+ QVERIFY(textinputObject->selectedText().isNull());
+ textinputObject->select(-10,0);
+ QVERIFY(textinputObject->selectedText().isNull());
+ textinputObject->select(100,110);
+ QVERIFY(textinputObject->selectedText().isNull());
+ textinputObject->select(0,-10);
+ QVERIFY(textinputObject->selectedText().isNull());
+ textinputObject->select(0,100);
+ QVERIFY(textinputObject->selectedText().isNull());
+ textinputObject->select(0,10);
+ QVERIFY(textinputObject->selectedText().size() == 10);
+ textinputObject->select(-10,10);
+ QVERIFY(textinputObject->selectedText().size() == 10);
+ textinputObject->select(100,101);
+ QVERIFY(textinputObject->selectedText().size() == 10);
+ textinputObject->select(0,-10);
+ QVERIFY(textinputObject->selectedText().size() == 10);
+ textinputObject->select(0,100);
+ QVERIFY(textinputObject->selectedText().size() == 10);
+
+ textinputObject->deselect();
+ QVERIFY(textinputObject->selectedText().isNull());
+ textinputObject->select(0,10);
+ QVERIFY(textinputObject->selectedText().size() == 10);
+ textinputObject->deselect();
+ QVERIFY(textinputObject->selectedText().isNull());
+
+ delete textinputObject;
+}
+
+void tst_qsgtextinput::isRightToLeft_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<bool>("emptyString");
+ QTest::addColumn<bool>("firstCharacter");
+ QTest::addColumn<bool>("lastCharacter");
+ QTest::addColumn<bool>("middleCharacter");
+ QTest::addColumn<bool>("startString");
+ QTest::addColumn<bool>("midString");
+ QTest::addColumn<bool>("endString");
+
+ const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647};
+ QTest::newRow("Empty") << "" << false << false << false << false << false << false << false;
+ QTest::newRow("Neutral") << "23244242" << false << false << false << false << false << false << false;
+ QTest::newRow("LTR") << "Hello world" << false << false << false << false << false << false << false;
+ QTest::newRow("RTL") << QString::fromUtf16(arabic_str, 11) << false << true << true << true << true << true << true;
+ QTest::newRow("Bidi RTL + LTR + RTL") << QString::fromUtf16(arabic_str, 11) + QString("Hello world") + QString::fromUtf16(arabic_str, 11) << false << true << true << false << true << true << true;
+ QTest::newRow("Bidi LTR + RTL + LTR") << QString("Hello world") + QString::fromUtf16(arabic_str, 11) + QString("Hello world") << false << false << false << true << false << false << false;
+}
+
+void tst_qsgtextinput::isRightToLeft()
+{
+ QFETCH(QString, text);
+ QFETCH(bool, emptyString);
+ QFETCH(bool, firstCharacter);
+ QFETCH(bool, lastCharacter);
+ QFETCH(bool, middleCharacter);
+ QFETCH(bool, startString);
+ QFETCH(bool, midString);
+ QFETCH(bool, endString);
+
+ QSGTextInput textInput;
+ textInput.setText(text);
+
+ // first test that the right string is delivered to the QString::isRightToLeft()
+ QCOMPARE(textInput.isRightToLeft(0,0), text.mid(0,0).isRightToLeft());
+ QCOMPARE(textInput.isRightToLeft(0,1), text.mid(0,1).isRightToLeft());
+ QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft());
+ QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft());
+ QCOMPARE(textInput.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft());
+ QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft());
+ if (text.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start.");
+ QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft());
+
+ // then test that the feature actually works
+ QCOMPARE(textInput.isRightToLeft(0,0), emptyString);
+ QCOMPARE(textInput.isRightToLeft(0,1), firstCharacter);
+ QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), lastCharacter);
+ QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter);
+ QCOMPARE(textInput.isRightToLeft(0,text.count()/4), startString);
+ QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), midString);
+ if (text.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start.");
+ QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), endString);
+}
+
+void tst_qsgtextinput::moveCursorSelection_data()
+{
+ QTest::addColumn<QString>("testStr");
+ QTest::addColumn<int>("cursorPosition");
+ QTest::addColumn<int>("movePosition");
+ QTest::addColumn<QSGTextInput::SelectionMode>("mode");
+ QTest::addColumn<int>("selectionStart");
+ QTest::addColumn<int>("selectionEnd");
+ QTest::addColumn<bool>("reversible");
+
+ // () contains the text selected by the cursor.
+ // <> contains the actual selection.
+
+ QTest::newRow("(t)he|characters")
+ << standard[0] << 0 << 1 << QSGTextInput::SelectCharacters << 0 << 1 << true;
+ QTest::newRow("do(g)|characters")
+ << standard[0] << 43 << 44 << QSGTextInput::SelectCharacters << 43 << 44 << true;
+ QTest::newRow("jum(p)ed|characters")
+ << standard[0] << 23 << 24 << QSGTextInput::SelectCharacters << 23 << 24 << true;
+ QTest::newRow("jumped( )over|characters")
+ << standard[0] << 26 << 27 << QSGTextInput::SelectCharacters << 26 << 27 << true;
+ QTest::newRow("(the )|characters")
+ << standard[0] << 0 << 4 << QSGTextInput::SelectCharacters << 0 << 4 << true;
+ QTest::newRow("( dog)|characters")
+ << standard[0] << 40 << 44 << QSGTextInput::SelectCharacters << 40 << 44 << true;
+ QTest::newRow("( jumped )|characters")
+ << standard[0] << 19 << 27 << QSGTextInput::SelectCharacters << 19 << 27 << true;
+ QTest::newRow("th(e qu)ick|characters")
+ << standard[0] << 2 << 6 << QSGTextInput::SelectCharacters << 2 << 6 << true;
+ QTest::newRow("la(zy d)og|characters")
+ << standard[0] << 38 << 42 << QSGTextInput::SelectCharacters << 38 << 42 << true;
+ QTest::newRow("jum(ped ov)er|characters")
+ << standard[0] << 23 << 29 << QSGTextInput::SelectCharacters << 23 << 29 << true;
+ QTest::newRow("()the|characters")
+ << standard[0] << 0 << 0 << QSGTextInput::SelectCharacters << 0 << 0 << true;
+ QTest::newRow("dog()|characters")
+ << standard[0] << 44 << 44 << QSGTextInput::SelectCharacters << 44 << 44 << true;
+ QTest::newRow("jum()ped|characters")
+ << standard[0] << 23 << 23 << QSGTextInput::SelectCharacters << 23 << 23 << true;
+
+ QTest::newRow("<(t)he>|words")
+ << standard[0] << 0 << 1 << QSGTextInput::SelectWords << 0 << 3 << true;
+ QTest::newRow("<do(g)>|words")
+ << standard[0] << 43 << 44 << QSGTextInput::SelectWords << 41 << 44 << true;
+ QTest::newRow("<jum(p)ed>|words")
+ << standard[0] << 23 << 24 << QSGTextInput::SelectWords << 20 << 26 << true;
+ QTest::newRow("<jumped( )>over|words,ltr")
+ << standard[0] << 26 << 27 << QSGTextInput::SelectWords << 20 << 27 << false;
+ QTest::newRow("jumped<( )over>|words,rtl")
+ << standard[0] << 27 << 26 << QSGTextInput::SelectWords << 26 << 31 << false;
+ QTest::newRow("<(the )>quick|words,ltr")
+ << standard[0] << 0 << 4 << QSGTextInput::SelectWords << 0 << 4 << false;
+ QTest::newRow("<(the )quick>|words,rtl")
+ << standard[0] << 4 << 0 << QSGTextInput::SelectWords << 0 << 9 << false;
+ QTest::newRow("<lazy( dog)>|words,ltr")
+ << standard[0] << 40 << 44 << QSGTextInput::SelectWords << 36 << 44 << false;
+ QTest::newRow("lazy<( dog)>|words,rtl")
+ << standard[0] << 44 << 40 << QSGTextInput::SelectWords << 40 << 44 << false;
+ QTest::newRow("<fox( jumped )>over|words,ltr")
+ << standard[0] << 19 << 27 << QSGTextInput::SelectWords << 16 << 27 << false;
+ QTest::newRow("fox<( jumped )over>|words,rtl")
+ << standard[0] << 27 << 19 << QSGTextInput::SelectWords << 19 << 31 << false;
+ QTest::newRow("<th(e qu)ick>|words")
+ << standard[0] << 2 << 6 << QSGTextInput::SelectWords << 0 << 9 << true;
+ QTest::newRow("<la(zy d)og|words>")
+ << standard[0] << 38 << 42 << QSGTextInput::SelectWords << 36 << 44 << true;
+ QTest::newRow("<jum(ped ov)er>|words")
+ << standard[0] << 23 << 29 << QSGTextInput::SelectWords << 20 << 31 << true;
+ QTest::newRow("<()>the|words")
+ << standard[0] << 0 << 0 << QSGTextInput::SelectWords << 0 << 0 << true;
+ QTest::newRow("dog<()>|words")
+ << standard[0] << 44 << 44 << QSGTextInput::SelectWords << 44 << 44 << true;
+ QTest::newRow("jum<()>ped|words")
+ << standard[0] << 23 << 23 << QSGTextInput::SelectWords << 23 << 23 << true;
+
+ QTest::newRow("Hello<(,)> |words")
+ << standard[2] << 5 << 6 << QSGTextInput::SelectWords << 5 << 6 << true;
+ QTest::newRow("Hello<(, )>world|words,ltr")
+ << standard[2] << 5 << 7 << QSGTextInput::SelectWords << 5 << 7 << false;
+ QTest::newRow("Hello<(, )world>|words,rtl")
+ << standard[2] << 7 << 5 << QSGTextInput::SelectWords << 5 << 12 << false;
+ QTest::newRow("<Hel(lo, )>world|words,ltr")
+ << standard[2] << 3 << 7 << QSGTextInput::SelectWords << 0 << 7 << false;
+ QTest::newRow("<Hel(lo, )world>|words,rtl")
+ << standard[2] << 7 << 3 << QSGTextInput::SelectWords << 0 << 12 << false;
+ QTest::newRow("<Hel(lo)>,|words")
+ << standard[2] << 3 << 5 << QSGTextInput::SelectWords << 0 << 5 << true;
+ QTest::newRow("Hello<()>,|words")
+ << standard[2] << 5 << 5 << QSGTextInput::SelectWords << 5 << 5 << true;
+ QTest::newRow("Hello,<()>|words")
+ << standard[2] << 6 << 6 << QSGTextInput::SelectWords << 6 << 6 << true;
+ QTest::newRow("Hello<,( )>world|words,ltr")
+ << standard[2] << 6 << 7 << QSGTextInput::SelectWords << 5 << 7 << false;
+ QTest::newRow("Hello,<( )world>|words,rtl")
+ << standard[2] << 7 << 6 << QSGTextInput::SelectWords << 6 << 12 << false;
+ QTest::newRow("Hello<,( world)>|words,ltr")
+ << standard[2] << 6 << 12 << QSGTextInput::SelectWords << 5 << 12 << false;
+ QTest::newRow("Hello,<( world)>|words,rtl")
+ << standard[2] << 12 << 6 << QSGTextInput::SelectWords << 6 << 12 << false;
+ QTest::newRow("Hello<,( world!)>|words,ltr")
+ << standard[2] << 6 << 13 << QSGTextInput::SelectWords << 5 << 13 << false;
+ QTest::newRow("Hello,<( world!)>|words,rtl")
+ << standard[2] << 13 << 6 << QSGTextInput::SelectWords << 6 << 13 << false;
+ QTest::newRow("Hello<(, world!)>|words")
+ << standard[2] << 5 << 13 << QSGTextInput::SelectWords << 5 << 13 << true;
+ // Fails due to an issue with QTextBoundaryFinder and punctuation at the end of strings.
+ // QTBUG-11365
+ // QTest::newRow("world<(!)>|words")
+ // << standard[2] << 12 << 13 << QSGTextInput::SelectWords << 12 << 13 << true;
+ QTest::newRow("world!<()>)|words")
+ << standard[2] << 13 << 13 << QSGTextInput::SelectWords << 13 << 13 << true;
+ QTest::newRow("world<()>!)|words")
+ << standard[2] << 12 << 12 << QSGTextInput::SelectWords << 12 << 12 << true;
+
+ QTest::newRow("<(,)>olleH |words")
+ << standard[3] << 7 << 8 << QSGTextInput::SelectWords << 7 << 8 << true;
+ QTest::newRow("<dlrow( ,)>olleH|words,ltr")
+ << standard[3] << 6 << 8 << QSGTextInput::SelectWords << 1 << 8 << false;
+ QTest::newRow("dlrow<( ,)>olleH|words,rtl")
+ << standard[3] << 8 << 6 << QSGTextInput::SelectWords << 6 << 8 << false;
+ QTest::newRow("<dlrow( ,ol)leH>|words,ltr")
+ << standard[3] << 6 << 10 << QSGTextInput::SelectWords << 1 << 13 << false;
+ QTest::newRow("dlrow<( ,ol)leH>|words,rtl")
+ << standard[3] << 10 << 6 << QSGTextInput::SelectWords << 6 << 13 << false;
+ QTest::newRow(",<(ol)leH>,|words")
+ << standard[3] << 8 << 10 << QSGTextInput::SelectWords << 8 << 13 << true;
+ QTest::newRow(",<()>olleH|words")
+ << standard[3] << 8 << 8 << QSGTextInput::SelectWords << 8 << 8 << true;
+ QTest::newRow("<()>,olleH|words")
+ << standard[3] << 7 << 7 << QSGTextInput::SelectWords << 7 << 7 << true;
+ QTest::newRow("<dlrow( )>,olleH|words,ltr")
+ << standard[3] << 6 << 7 << QSGTextInput::SelectWords << 1 << 7 << false;
+ QTest::newRow("dlrow<( ),>olleH|words,rtl")
+ << standard[3] << 7 << 6 << QSGTextInput::SelectWords << 6 << 8 << false;
+ QTest::newRow("<(dlrow )>,olleH|words,ltr")
+ << standard[3] << 1 << 7 << QSGTextInput::SelectWords << 1 << 7 << false;
+ QTest::newRow("<(dlrow ),>olleH|words,rtl")
+ << standard[3] << 7 << 1 << QSGTextInput::SelectWords << 1 << 8 << false;
+ QTest::newRow("<(!dlrow )>,olleH|words,ltr")
+ << standard[3] << 0 << 7 << QSGTextInput::SelectWords << 0 << 7 << false;
+ QTest::newRow("<(!dlrow ),>olleH|words,rtl")
+ << standard[3] << 7 << 0 << QSGTextInput::SelectWords << 0 << 8 << false;
+ QTest::newRow("(!dlrow ,)olleH|words")
+ << standard[3] << 0 << 8 << QSGTextInput::SelectWords << 0 << 8 << true;
+ QTest::newRow("<(!)>dlrow|words")
+ << standard[3] << 0 << 1 << QSGTextInput::SelectWords << 0 << 1 << true;
+ QTest::newRow("<()>!dlrow|words")
+ << standard[3] << 0 << 0 << QSGTextInput::SelectWords << 0 << 0 << true;
+ QTest::newRow("!<()>dlrow|words")
+ << standard[3] << 1 << 1 << QSGTextInput::SelectWords << 1 << 1 << true;
+
+ QTest::newRow(" <s(pac)ey> text |words")
+ << standard[4] << 1 << 4 << QSGTextInput::SelectWords << 1 << 7 << true;
+ QTest::newRow(" spacey <t(ex)t> |words")
+ << standard[4] << 11 << 13 << QSGTextInput::SelectWords << 10 << 14 << false; // Should be reversible. QTBUG-11365
+ QTest::newRow("<( )>spacey text |words|ltr")
+ << standard[4] << 0 << 1 << QSGTextInput::SelectWords << 0 << 1 << false;
+ QTest::newRow("<( )spacey> text |words|rtl")
+ << standard[4] << 1 << 0 << QSGTextInput::SelectWords << 0 << 7 << false;
+ QTest::newRow("spacey <text( )>|words|ltr")
+ << standard[4] << 14 << 15 << QSGTextInput::SelectWords << 10 << 15 << false;
+// QTBUG-11365
+// QTest::newRow("spacey text<( )>|words|rtl")
+// << standard[4] << 15 << 14 << QSGTextInput::SelectWords << 14 << 15 << false;
+ QTest::newRow("<()> spacey text |words")
+ << standard[4] << 0 << 0 << QSGTextInput::SelectWords << 0 << 0 << false;
+ QTest::newRow(" spacey text <()>|words")
+ << standard[4] << 15 << 15 << QSGTextInput::SelectWords << 15 << 15 << false;
+}
+
+void tst_qsgtextinput::moveCursorSelection()
+{
+ QFETCH(QString, testStr);
+ QFETCH(int, cursorPosition);
+ QFETCH(int, movePosition);
+ QFETCH(QSGTextInput::SelectionMode, mode);
+ QFETCH(int, selectionStart);
+ QFETCH(int, selectionEnd);
+ QFETCH(bool, reversible);
+
+ QString componentStr = "import QtQuick 2.0\nTextInput { text: \""+ testStr +"\"; }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+ QVERIFY(textinputObject != 0);
+
+ textinputObject->setCursorPosition(cursorPosition);
+ textinputObject->moveCursorSelection(movePosition, mode);
+
+ QCOMPARE(textinputObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
+ QCOMPARE(textinputObject->selectionStart(), selectionStart);
+ QCOMPARE(textinputObject->selectionEnd(), selectionEnd);
+
+ if (reversible) {
+ textinputObject->setCursorPosition(movePosition);
+ textinputObject->moveCursorSelection(cursorPosition, mode);
+
+ QCOMPARE(textinputObject->selectedText(), testStr.mid(selectionStart, selectionEnd - selectionStart));
+ QCOMPARE(textinputObject->selectionStart(), selectionStart);
+ QCOMPARE(textinputObject->selectionEnd(), selectionEnd);
+ }
+
+ delete textinputObject;
+}
+
+void tst_qsgtextinput::moveCursorSelectionSequence_data()
+{
+ QTest::addColumn<QString>("testStr");
+ QTest::addColumn<int>("cursorPosition");
+ QTest::addColumn<int>("movePosition1");
+ QTest::addColumn<int>("movePosition2");
+ QTest::addColumn<int>("selection1Start");
+ QTest::addColumn<int>("selection1End");
+ QTest::addColumn<int>("selection2Start");
+ QTest::addColumn<int>("selection2End");
+
+ // () contains the text selected by the cursor.
+ // <> contains the actual selection.
+ // ^ is the revised cursor position.
+ // {} contains the revised selection.
+
+ QTest::newRow("the {<quick( bro)wn> f^ox} jumped|ltr")
+ << standard[0]
+ << 9 << 13 << 17
+ << 4 << 15
+ << 4 << 19;
+ QTest::newRow("the quick<( {bro)wn> f^ox} jumped|rtl")
+ << standard[0]
+ << 13 << 9 << 17
+ << 9 << 15
+ << 10 << 19;
+ QTest::newRow("the {<quick( bro)wn> ^}fox jumped|ltr")
+ << standard[0]
+ << 9 << 13 << 16
+ << 4 << 15
+ << 4 << 16;
+ QTest::newRow("the quick<( {bro)wn> ^}fox jumped|rtl")
+ << standard[0]
+ << 13 << 9 << 16
+ << 9 << 15
+ << 10 << 16;
+ QTest::newRow("the {<quick( bro)wn^>} fox jumped|ltr")
+ << standard[0]
+ << 9 << 13 << 15
+ << 4 << 15
+ << 4 << 15;
+ QTest::newRow("the quick<( {bro)wn^>} f^ox jumped|rtl")
+ << standard[0]
+ << 13 << 9 << 15
+ << 9 << 15
+ << 10 << 15;
+ QTest::newRow("the {<quick() ^}bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 10
+ << 4 << 15
+ << 4 << 10;
+ QTest::newRow("the quick<( {^bro)wn>} fox|rtl")
+ << standard[0]
+ << 13 << 9 << 10
+ << 9 << 15
+ << 10 << 15;
+ QTest::newRow("the {<quick^}( bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 9
+ << 4 << 15
+ << 4 << 9;
+ QTest::newRow("the quick{<(^ bro)wn>} fox|rtl")
+ << standard[0]
+ << 13 << 9 << 9
+ << 9 << 15
+ << 9 << 15;
+ QTest::newRow("the {<qui^ck}( bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 7
+ << 4 << 15
+ << 4 << 9;
+ QTest::newRow("the {<qui^ck}( bro)wn> fox|rtl")
+ << standard[0]
+ << 13 << 9 << 7
+ << 9 << 15
+ << 4 << 15;
+ QTest::newRow("the {<^quick}( bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 4
+ << 4 << 15
+ << 4 << 9;
+ QTest::newRow("the {<^quick}( bro)wn> fox|rtl")
+ << standard[0]
+ << 13 << 9 << 4
+ << 9 << 15
+ << 4 << 15;
+ QTest::newRow("the{^ <quick}( bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 3
+ << 4 << 15
+ << 3 << 9;
+ QTest::newRow("the{^ <quick}( bro)wn> fox|rtl")
+ << standard[0]
+ << 13 << 9 << 3
+ << 9 << 15
+ << 3 << 15;
+ QTest::newRow("{t^he <quick}( bro)wn> fox|ltr")
+ << standard[0]
+ << 9 << 13 << 1
+ << 4 << 15
+ << 0 << 9;
+ QTest::newRow("{t^he <quick}( bro)wn> fox|rtl")
+ << standard[0]
+ << 13 << 9 << 1
+ << 9 << 15
+ << 0 << 15;
+
+ QTest::newRow("{<He(ll)o>, w^orld}!|ltr")
+ << standard[2]
+ << 2 << 4 << 8
+ << 0 << 5
+ << 0 << 12;
+ QTest::newRow("{<He(ll)o>, w^orld}!|rtl")
+ << standard[2]
+ << 4 << 2 << 8
+ << 0 << 5
+ << 0 << 12;
+
+ QTest::newRow("!{dlro^w ,<o(ll)eH>}|ltr")
+ << standard[3]
+ << 9 << 11 << 5
+ << 8 << 13
+ << 1 << 13;
+ QTest::newRow("!{dlro^w ,<o(ll)eH>}|rtl")
+ << standard[3]
+ << 11 << 9 << 5
+ << 8 << 13
+ << 1 << 13;
+
+ QTest::newRow("{<(^} sp)acey> text |ltr")
+ << standard[4]
+ << 0 << 3 << 0
+ << 0 << 7
+ << 0 << 0;
+ QTest::newRow("{<( ^}sp)acey> text |ltr")
+ << standard[4]
+ << 0 << 3 << 1
+ << 0 << 7
+ << 0 << 1;
+ QTest::newRow("<( {s^p)acey>} text |rtl")
+ << standard[4]
+ << 3 << 0 << 2
+ << 0 << 7
+ << 1 << 7;
+ QTest::newRow("<( {^sp)acey>} text |rtl")
+ << standard[4]
+ << 3 << 0 << 1
+ << 0 << 7
+ << 1 << 7;
+
+ QTest::newRow(" spacey <te(xt {^)>}|rtl")
+ << standard[4]
+ << 15 << 12 << 15
+ << 10 << 15
+ << 15 << 15;
+// QTBUG-11365
+// QTest::newRow(" spacey <te(xt{^ )>}|rtl")
+// << standard[4]
+// << 15 << 12 << 14
+// << 10 << 15
+// << 14 << 15;
+ QTest::newRow(" spacey {<te(x^t} )>|ltr")
+ << standard[4]
+ << 12 << 15 << 13
+ << 10 << 15
+ << 10 << 14;
+// QTBUG-11365
+// QTest::newRow(" spacey {<te(xt^} )>|ltr")
+// << standard[4]
+// << 12 << 15 << 14
+// << 10 << 15
+// << 10 << 14;
+}
+
+void tst_qsgtextinput::moveCursorSelectionSequence()
+{
+ QFETCH(QString, testStr);
+ QFETCH(int, cursorPosition);
+ QFETCH(int, movePosition1);
+ QFETCH(int, movePosition2);
+ QFETCH(int, selection1Start);
+ QFETCH(int, selection1End);
+ QFETCH(int, selection2Start);
+ QFETCH(int, selection2End);
+
+ QString componentStr = "import QtQuick 2.0\nTextInput { text: \""+ testStr +"\"; }";
+ QDeclarativeComponent textinputComponent(&engine);
+ textinputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput*>(textinputComponent.create());
+ QVERIFY(textinputObject != 0);
+
+ textinputObject->setCursorPosition(cursorPosition);
+
+ textinputObject->moveCursorSelection(movePosition1, QSGTextInput::SelectWords);
+ QCOMPARE(textinputObject->selectedText(), testStr.mid(selection1Start, selection1End - selection1Start));
+ QCOMPARE(textinputObject->selectionStart(), selection1Start);
+ QCOMPARE(textinputObject->selectionEnd(), selection1End);
+
+ textinputObject->moveCursorSelection(movePosition2, QSGTextInput::SelectWords);
+ QCOMPARE(textinputObject->selectedText(), testStr.mid(selection2Start, selection2End - selection2Start));
+ QCOMPARE(textinputObject->selectionStart(), selection2Start);
+ QCOMPARE(textinputObject->selectionEnd(), selection2End);
+
+ delete textinputObject;
+}
+
+void tst_qsgtextinput::dragMouseSelection()
+{
+ QString qmlfile = SRCDIR "/data/mouseselection_true.qml";
+
+ QSGView canvas(QUrl::fromLocalFile(qmlfile));
+
+ canvas.show();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+
+ QVERIFY(canvas.rootObject() != 0);
+ QSGTextInput *textInputObject = qobject_cast<QSGTextInput *>(canvas.rootObject());
+ QVERIFY(textInputObject != 0);
+
+ // press-and-drag-and-release from x1 to x2
+ int x1 = 10;
+ int x2 = 70;
+ int y = textInputObject->height()/2;
+ QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(x2,y), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&canvas, &mv);
+ }
+ QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
+
+ QString str1 = textInputObject->selectedText();
+ QVERIFY(str1.length() > 3);
+
+ // press and drag the current selection.
+ x1 = 40;
+ x2 = 100;
+ QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(x2,y), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&canvas, &mv);
+ }
+ QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
+ QString str2 = textInputObject->selectedText();
+ QVERIFY(str2.length() > 3);
+
+ QVERIFY(str1 != str2); // Verify the second press and drag is a new selection and doesn't not the first moved.
+}
+
+void tst_qsgtextinput::mouseSelectionMode_data()
+{
+ QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<bool>("selectWords");
+
+ // import installed
+ QTest::newRow("SelectWords") << SRCDIR "/data/mouseselectionmode_words.qml" << true;
+ QTest::newRow("SelectCharacters") << SRCDIR "/data/mouseselectionmode_characters.qml" << false;
+ QTest::newRow("default") << SRCDIR "/data/mouseselectionmode_default.qml" << false;
+}
+
+void tst_qsgtextinput::mouseSelectionMode()
+{
+ QFETCH(QString, qmlfile);
+ QFETCH(bool, selectWords);
+
+ QString text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ QSGView canvas(QUrl::fromLocalFile(qmlfile));
+
+ canvas.show();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+
+ QVERIFY(canvas.rootObject() != 0);
+ QSGTextInput *textInputObject = qobject_cast<QSGTextInput *>(canvas.rootObject());
+ QVERIFY(textInputObject != 0);
+
+ // press-and-drag-and-release from x1 to x2
+ int x1 = 10;
+ int x2 = 70;
+ int y = textInputObject->height()/2;
+ QTest::mousePress(&canvas, Qt::LeftButton, 0, QPoint(x1,y));
+ //QTest::mouseMove(&canvas, canvas.mapFromScene(QPoint(x2,y))); // doesn't work
+ QMouseEvent mv(QEvent::MouseMove, QPoint(x2,y), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&canvas, &mv);
+ QTest::mouseRelease(&canvas, Qt::LeftButton, 0, QPoint(x2,y));
+ QString str = textInputObject->selectedText();
+ if (selectWords) {
+ QCOMPARE(str, text);
+ } else {
+ QVERIFY(str.length() > 3);
+ QVERIFY(str != text);
+ }
+}
+
+void tst_qsgtextinput::horizontalAlignment_data()
+{
+ QTest::addColumn<int>("hAlign");
+ QTest::addColumn<QString>("expectfile");
+
+ QTest::newRow("L") << int(Qt::AlignLeft) << "halign_left";
+ QTest::newRow("R") << int(Qt::AlignRight) << "halign_right";
+ QTest::newRow("C") << int(Qt::AlignHCenter) << "halign_center";
+}
+
+void tst_qsgtextinput::horizontalAlignment()
+{
+ QFETCH(int, hAlign);
+ QFETCH(QString, expectfile);
+
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/horizontalAlignment.qml"));
+
+ canvas.show();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+ QObject *ob = canvas.rootObject();
+ QVERIFY(ob != 0);
+ ob->setProperty("horizontalAlignment",hAlign);
+ QImage actual(canvas.width(), canvas.height(), QImage::Format_RGB32);
+ actual.fill(qRgb(255,255,255));
+ {
+ QPainter p(&actual);
+ canvas.render(&p);
+ }
+
+ expectfile = createExpectedFileIfNotFound(expectfile, actual);
+
+ QImage expect(expectfile);
+
+ QCOMPARE(actual,expect);
+}
+
+void tst_qsgtextinput::horizontalAlignment_RightToLeft()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/horizontalAlignment_RightToLeft.qml"));
+ QSGTextInput *textInput = canvas.rootObject()->findChild<QSGTextInput*>("text");
+ QVERIFY(textInput != 0);
+ canvas.show();
+
+ QSGTextInputPrivate *textInputPrivate = QSGTextInputPrivate::get(textInput);
+ QVERIFY(textInputPrivate != 0);
+ QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+
+ // implicit alignment should follow the reading direction of RTL text
+ QCOMPARE(textInput->hAlign(), QSGTextInput::AlignRight);
+ QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
+ QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+
+ // explicitly left aligned
+ textInput->setHAlign(QSGTextInput::AlignLeft);
+ QCOMPARE(textInput->hAlign(), QSGTextInput::AlignLeft);
+ QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
+ QVERIFY(-textInputPrivate->hscroll < canvas.width()/2);
+
+ // explicitly right aligned
+ textInput->setHAlign(QSGTextInput::AlignRight);
+ QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
+ QCOMPARE(textInput->hAlign(), QSGTextInput::AlignRight);
+ QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+
+ // explicitly center aligned
+ textInput->setHAlign(QSGTextInput::AlignHCenter);
+ QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
+ QCOMPARE(textInput->hAlign(), QSGTextInput::AlignHCenter);
+ QVERIFY(-textInputPrivate->hscroll < canvas.width()/2);
+ QVERIFY(-textInputPrivate->hscroll + textInputPrivate->width > canvas.width()/2);
+
+ // reseted alignment should go back to following the text reading direction
+ textInput->resetHAlign();
+ QCOMPARE(textInput->hAlign(), QSGTextInput::AlignRight);
+ QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
+ QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+
+ // mirror the text item
+ QSGItemPrivate::get(textInput)->setLayoutMirror(true);
+
+ // mirrored implicit alignment should continue to follow the reading direction of the text
+ QCOMPARE(textInput->hAlign(), QSGTextInput::AlignRight);
+ QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
+ QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+
+ // explicitly right aligned behaves as left aligned
+ textInput->setHAlign(QSGTextInput::AlignRight);
+ QCOMPARE(textInput->hAlign(), QSGTextInput::AlignRight);
+ QCOMPARE(textInput->effectiveHAlign(), QSGTextInput::AlignLeft);
+ QVERIFY(-textInputPrivate->hscroll < canvas.width()/2);
+
+ // mirrored explicitly left aligned behaves as right aligned
+ textInput->setHAlign(QSGTextInput::AlignLeft);
+ QCOMPARE(textInput->hAlign(), QSGTextInput::AlignLeft);
+ QCOMPARE(textInput->effectiveHAlign(), QSGTextInput::AlignRight);
+ QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+
+ // disable mirroring
+ QSGItemPrivate::get(textInput)->setLayoutMirror(false);
+ QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
+ textInput->resetHAlign();
+
+ // English text should be implicitly left aligned
+ textInput->setText("Hello world!");
+ QCOMPARE(textInput->hAlign(), QSGTextInput::AlignLeft);
+ QVERIFY(-textInputPrivate->hscroll < canvas.width()/2);
+
+#ifndef Q_OS_MAC // QTBUG-18040
+ // empty text with implicit alignment follows the system locale-based
+ // keyboard input direction from QApplication::keyboardInputDirection
+ textInput->setText("");
+ QCOMPARE(textInput->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
+ QSGTextInput::AlignLeft : QSGTextInput::AlignRight);
+ if (QApplication::keyboardInputDirection() == Qt::LeftToRight)
+ QVERIFY(-textInputPrivate->hscroll < canvas.width()/2);
+ else
+ QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+ textInput->setHAlign(QSGTextInput::AlignRight);
+ QCOMPARE(textInput->hAlign(), QSGTextInput::AlignRight);
+ QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+#endif
+
+#ifndef Q_OS_MAC // QTBUG-18040
+ // alignment of TextInput with no text set to it
+ QString componentStr = "import QtQuick 2.0\nTextInput {}";
+ QDeclarativeComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QSGTextInput *textObject = qobject_cast<QSGTextInput*>(textComponent.create());
+ QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
+ QSGTextInput::AlignLeft : QSGTextInput::AlignRight);
+ delete textObject;
+#endif
+}
+
+void tst_qsgtextinput::positionAt()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/positionAt.qml"));
+ QVERIFY(canvas.rootObject() != 0);
+ canvas.show();
+ canvas.setFocus();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput *>(canvas.rootObject());
+ QVERIFY(textinputObject != 0);
+
+ // Check autoscrolled...
+ QFontMetrics fm(textinputObject->font());
+
+ int pos = textinputObject->positionAt(textinputObject->width()/2);
+ int diff = abs(int(fm.width(textinputObject->text()) - (fm.width(textinputObject->text().left(pos))+textinputObject->width()/2)));
+
+ // some tollerance for different fonts.
+#ifdef Q_OS_LINUX
+ QVERIFY(diff < 2);
+#else
+ QVERIFY(diff < 5);
+#endif
+
+ int x = textinputObject->positionToRectangle(pos + 1).x() - 1;
+ QCOMPARE(textinputObject->positionAt(x, QSGTextInput::CursorBetweenCharacters), pos + 1);
+ QCOMPARE(textinputObject->positionAt(x, QSGTextInput::CursorOnCharacter), pos);
+
+ // Check without autoscroll...
+ textinputObject->setAutoScroll(false);
+ pos = textinputObject->positionAt(textinputObject->width()/2);
+ diff = abs(int(fm.width(textinputObject->text().left(pos))-textinputObject->width()/2));
+
+ // some tollerance for different fonts.
+#ifdef Q_OS_LINUX
+ QVERIFY(diff < 2);
+#else
+ QVERIFY(diff < 5);
+#endif
+
+ x = textinputObject->positionToRectangle(pos + 1).x() - 1;
+ QCOMPARE(textinputObject->positionAt(x, QSGTextInput::CursorBetweenCharacters), pos + 1);
+ QCOMPARE(textinputObject->positionAt(x, QSGTextInput::CursorOnCharacter), pos);
+
+ const qreal x0 = textinputObject->positionToRectangle(pos).x();
+ const qreal x1 = textinputObject->positionToRectangle(pos + 1).x();
+
+ QString preeditText = textinputObject->text().mid(0, pos);
+ textinputObject->setText(textinputObject->text().mid(pos));
+ textinputObject->setCursorPosition(0);
+
+ QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>());
+ QApplication::sendEvent(&canvas, &inputEvent);
+
+ // Check all points within the preedit text return the same position.
+ QCOMPARE(textinputObject->positionAt(0), 0);
+ QCOMPARE(textinputObject->positionAt(x0 / 2), 0);
+ QCOMPARE(textinputObject->positionAt(x0), 0);
+
+ // Verify positioning returns to normal after the preedit text.
+ QCOMPARE(textinputObject->positionAt(x1), 1);
+ QCOMPARE(textinputObject->positionToRectangle(1).x(), x1);
+}
+
+void tst_qsgtextinput::maxLength()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/maxLength.qml"));
+ QVERIFY(canvas.rootObject() != 0);
+ canvas.show();
+ canvas.setFocus();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput *>(canvas.rootObject());
+ QVERIFY(textinputObject != 0);
+ QVERIFY(textinputObject->text().isEmpty());
+ QVERIFY(textinputObject->maxLength() == 10);
+ foreach(const QString &str, standard){
+ QVERIFY(textinputObject->text().length() <= 10);
+ textinputObject->setText(str);
+ QVERIFY(textinputObject->text().length() <= 10);
+ }
+
+ textinputObject->setText("");
+ QTRY_VERIFY(textinputObject->hasActiveFocus() == true);
+ for(int i=0; i<20; i++){
+ QCOMPARE(textinputObject->text().length(), qMin(i,10));
+ //simulateKey(&canvas, Qt::Key_A);
+ QTest::keyPress(&canvas, Qt::Key_A);
+ QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
+ }
+}
+
+void tst_qsgtextinput::masks()
+{
+ //Not a comprehensive test of the possible masks, that's done elsewhere (QLineEdit)
+ //QString componentStr = "import QtQuick 2.0\nTextInput { inputMask: 'HHHHhhhh'; }";
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/masks.qml"));
+ canvas.show();
+ canvas.setFocus();
+ QVERIFY(canvas.rootObject() != 0);
+ QSGTextInput *textinputObject = qobject_cast<QSGTextInput *>(canvas.rootObject());
+ QVERIFY(textinputObject != 0);
+ QTRY_VERIFY(textinputObject->hasActiveFocus() == true);
+ QVERIFY(textinputObject->text().length() == 0);
+ QCOMPARE(textinputObject->inputMask(), QString("HHHHhhhh; "));
+ for(int i=0; i<10; i++){
+ QCOMPARE(qMin(i,8), textinputObject->text().length());
+ QCOMPARE(i>=4, textinputObject->hasAcceptableInput());
+ //simulateKey(&canvas, Qt::Key_A);
+ QTest::keyPress(&canvas, Qt::Key_A);
+ QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
+ }
+}
+
+void tst_qsgtextinput::validators()
+{
+ // Note that this test assumes that the validators are working properly
+ // so you may need to run their tests first. All validators are checked
+ // here to ensure that their exposure to QML is working.
+
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/validators.qml"));
+ canvas.show();
+ canvas.setFocus();
+
+ QVERIFY(canvas.rootObject() != 0);
+
+ QSGTextInput *intInput = qobject_cast<QSGTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("intInput")));
+ QVERIFY(intInput);
+ intInput->setFocus(true);
+ QTRY_VERIFY(intInput->hasActiveFocus());
+ QTest::keyPress(&canvas, Qt::Key_1);
+ QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
+ QCOMPARE(intInput->text(), QLatin1String("1"));
+ QCOMPARE(intInput->hasAcceptableInput(), false);
+ QTest::keyPress(&canvas, Qt::Key_2);
+ QTest::keyRelease(&canvas, Qt::Key_2, Qt::NoModifier ,10);
+ QCOMPARE(intInput->text(), QLatin1String("1"));
+ QCOMPARE(intInput->hasAcceptableInput(), false);
+ QTest::keyPress(&canvas, Qt::Key_1);
+ QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
+ QCOMPARE(intInput->text(), QLatin1String("11"));
+ QCOMPARE(intInput->hasAcceptableInput(), true);
+ QTest::keyPress(&canvas, Qt::Key_0);
+ QTest::keyRelease(&canvas, Qt::Key_0, Qt::NoModifier ,10);
+ QCOMPARE(intInput->text(), QLatin1String("11"));
+ QCOMPARE(intInput->hasAcceptableInput(), true);
+
+ QSGTextInput *dblInput = qobject_cast<QSGTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("dblInput")));
+ QTRY_VERIFY(dblInput);
+ dblInput->setFocus(true);
+ QVERIFY(dblInput->hasActiveFocus() == true);
+ QTest::keyPress(&canvas, Qt::Key_1);
+ QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
+ QCOMPARE(dblInput->text(), QLatin1String("1"));
+ QCOMPARE(dblInput->hasAcceptableInput(), false);
+ QTest::keyPress(&canvas, Qt::Key_2);
+ QTest::keyRelease(&canvas, Qt::Key_2, Qt::NoModifier ,10);
+ QCOMPARE(dblInput->text(), QLatin1String("12"));
+ QCOMPARE(dblInput->hasAcceptableInput(), true);
+ QTest::keyPress(&canvas, Qt::Key_Period);
+ QTest::keyRelease(&canvas, Qt::Key_Period, Qt::NoModifier ,10);
+ QCOMPARE(dblInput->text(), QLatin1String("12."));
+ QCOMPARE(dblInput->hasAcceptableInput(), true);
+ QTest::keyPress(&canvas, Qt::Key_1);
+ QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
+ QCOMPARE(dblInput->text(), QLatin1String("12.1"));
+ QCOMPARE(dblInput->hasAcceptableInput(), true);
+ QTest::keyPress(&canvas, Qt::Key_1);
+ QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
+ QCOMPARE(dblInput->text(), QLatin1String("12.11"));
+ QCOMPARE(dblInput->hasAcceptableInput(), true);
+ QTest::keyPress(&canvas, Qt::Key_1);
+ QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
+ QCOMPARE(dblInput->text(), QLatin1String("12.11"));
+ QCOMPARE(dblInput->hasAcceptableInput(), true);
+
+ QSGTextInput *strInput = qobject_cast<QSGTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("strInput")));
+ QTRY_VERIFY(strInput);
+ strInput->setFocus(true);
+ QVERIFY(strInput->hasActiveFocus() == true);
+ QTest::keyPress(&canvas, Qt::Key_1);
+ QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
+ QCOMPARE(strInput->text(), QLatin1String(""));
+ QCOMPARE(strInput->hasAcceptableInput(), false);
+ QTest::keyPress(&canvas, Qt::Key_A);
+ QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
+ QCOMPARE(strInput->text(), QLatin1String("a"));
+ QCOMPARE(strInput->hasAcceptableInput(), false);
+ QTest::keyPress(&canvas, Qt::Key_A);
+ QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
+ QCOMPARE(strInput->text(), QLatin1String("aa"));
+ QCOMPARE(strInput->hasAcceptableInput(), true);
+ QTest::keyPress(&canvas, Qt::Key_A);
+ QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
+ QCOMPARE(strInput->text(), QLatin1String("aaa"));
+ QCOMPARE(strInput->hasAcceptableInput(), true);
+ QTest::keyPress(&canvas, Qt::Key_A);
+ QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
+ QCOMPARE(strInput->text(), QLatin1String("aaaa"));
+ QCOMPARE(strInput->hasAcceptableInput(), true);
+ QTest::keyPress(&canvas, Qt::Key_A);
+ QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
+ QCOMPARE(strInput->text(), QLatin1String("aaaa"));
+ QCOMPARE(strInput->hasAcceptableInput(), true);
+}
+
+void tst_qsgtextinput::inputMethods()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/inputmethods.qml"));
+ canvas.show();
+ canvas.setFocus();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+
+ // test input method hints
+ QVERIFY(canvas.rootObject() != 0);
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(canvas.rootObject());
+ QVERIFY(input != 0);
+ QVERIFY(input->inputMethodHints() & Qt::ImhNoPredictiveText);
+ input->setInputMethodHints(Qt::ImhUppercaseOnly);
+ QVERIFY(input->inputMethodHints() & Qt::ImhUppercaseOnly);
+
+ input->setFocus(true);
+ QVERIFY(input->hasActiveFocus() == true);
+ // test that input method event is committed
+ QInputMethodEvent event;
+ event.setCommitString( "My ", -12, 0);
+ QApplication::sendEvent(&canvas, &event);
+ QCOMPARE(input->text(), QString("My Hello world!"));
+
+ input->setCursorPosition(2);
+ event.setCommitString("Your", -2, 2);
+ QApplication::sendEvent(&canvas, &event);
+ QCOMPARE(input->text(), QString("Your Hello world!"));
+ QCOMPARE(input->cursorPosition(), 4);
+
+ input->setCursorPosition(7);
+ event.setCommitString("Goodbye", -2, 5);
+ QApplication::sendEvent(&canvas, &event);
+ QCOMPARE(input->text(), QString("Your Goodbye world!"));
+ QCOMPARE(input->cursorPosition(), 12);
+
+ input->setCursorPosition(8);
+ event.setCommitString("Our", -8, 4);
+ QApplication::sendEvent(&canvas, &event);
+ QCOMPARE(input->text(), QString("Our Goodbye world!"));
+ QCOMPARE(input->cursorPosition(), 7);
+}
+
+/*
+TextInput element should only handle left/right keys until the cursor reaches
+the extent of the text, then they should ignore the keys.
+
+*/
+void tst_qsgtextinput::navigation()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/navigation.qml"));
+ canvas.show();
+ canvas.setFocus();
+
+ QVERIFY(canvas.rootObject() != 0);
+
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
+
+ QVERIFY(input != 0);
+ input->setCursorPosition(0);
+ QTRY_VERIFY(input->hasActiveFocus() == true);
+ simulateKey(&canvas, Qt::Key_Left);
+ QVERIFY(input->hasActiveFocus() == false);
+ simulateKey(&canvas, Qt::Key_Right);
+ QVERIFY(input->hasActiveFocus() == true);
+ //QT-2944: If text is selected, ensure we deselect upon cursor motion
+ input->setCursorPosition(input->text().length());
+ input->select(0,input->text().length());
+ QVERIFY(input->selectionStart() != input->selectionEnd());
+ simulateKey(&canvas, Qt::Key_Right);
+ QVERIFY(input->selectionStart() == input->selectionEnd());
+ QVERIFY(input->selectionStart() == input->text().length());
+ QVERIFY(input->hasActiveFocus() == true);
+ simulateKey(&canvas, Qt::Key_Right);
+ QVERIFY(input->hasActiveFocus() == false);
+ simulateKey(&canvas, Qt::Key_Left);
+ QVERIFY(input->hasActiveFocus() == true);
+
+ // Up and Down should NOT do Home/End, even on Mac OS X (QTBUG-10438).
+ input->setCursorPosition(2);
+ QCOMPARE(input->cursorPosition(),2);
+ simulateKey(&canvas, Qt::Key_Up);
+ QCOMPARE(input->cursorPosition(),2);
+ simulateKey(&canvas, Qt::Key_Down);
+ QCOMPARE(input->cursorPosition(),2);
+}
+
+void tst_qsgtextinput::navigation_RTL()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/navigation.qml"));
+ canvas.show();
+ canvas.setFocus();
+
+ QVERIFY(canvas.rootObject() != 0);
+
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
+
+ QVERIFY(input != 0);
+ const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647};
+ input->setText(QString::fromUtf16(arabic_str, 11));
+
+ input->setCursorPosition(0);
+ QTRY_VERIFY(input->hasActiveFocus() == true);
+
+ // move off
+ simulateKey(&canvas, Qt::Key_Right);
+ QVERIFY(input->hasActiveFocus() == false);
+
+ // move back
+ simulateKey(&canvas, Qt::Key_Left);
+ QVERIFY(input->hasActiveFocus() == true);
+
+ input->setCursorPosition(input->text().length());
+ QVERIFY(input->hasActiveFocus() == true);
+
+ // move off
+ simulateKey(&canvas, Qt::Key_Left);
+ QVERIFY(input->hasActiveFocus() == false);
+
+ // move back
+ simulateKey(&canvas, Qt::Key_Right);
+ QVERIFY(input->hasActiveFocus() == true);
+}
+
+void tst_qsgtextinput::copyAndPaste() {
+#ifndef QT_NO_CLIPBOARD
+
+#ifdef Q_WS_MAC
+ {
+ PasteboardRef pasteboard;
+ OSStatus status = PasteboardCreate(0, &pasteboard);
+ if (status == noErr)
+ CFRelease(pasteboard);
+ else
+ QSKIP("This machine doesn't support the clipboard", SkipAll);
+ }
+#endif
+
+ QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\" }";
+ QDeclarativeComponent textInputComponent(&engine);
+ textInputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textInput = qobject_cast<QSGTextInput*>(textInputComponent.create());
+ QVERIFY(textInput != 0);
+
+ // copy and paste
+ QCOMPARE(textInput->text().length(), 12);
+ textInput->select(0, textInput->text().length());;
+ textInput->copy();
+ QCOMPARE(textInput->selectedText(), QString("Hello world!"));
+ QCOMPARE(textInput->selectedText().length(), 12);
+ textInput->setCursorPosition(0);
+ QVERIFY(textInput->canPaste());
+ textInput->paste();
+ QCOMPARE(textInput->text(), QString("Hello world!Hello world!"));
+ QCOMPARE(textInput->text().length(), 24);
+
+ // can paste
+ QVERIFY(textInput->canPaste());
+ textInput->setReadOnly(true);
+ QVERIFY(!textInput->canPaste());
+ textInput->setReadOnly(false);
+ QVERIFY(textInput->canPaste());
+
+ // select word
+ textInput->setCursorPosition(0);
+ textInput->selectWord();
+ QCOMPARE(textInput->selectedText(), QString("Hello"));
+
+ // select all and cut
+ textInput->selectAll();
+ textInput->cut();
+ QCOMPARE(textInput->text().length(), 0);
+ textInput->paste();
+ QCOMPARE(textInput->text(), QString("Hello world!Hello world!"));
+ QCOMPARE(textInput->text().length(), 24);
+
+ // clear copy buffer
+ QClipboard *clipboard = QApplication::clipboard();
+ QVERIFY(clipboard);
+ clipboard->clear();
+ QVERIFY(!textInput->canPaste());
+
+ // test that copy functionality is disabled
+ // when echo mode is set to hide text/password mode
+ int index = 0;
+ while (index < 4) {
+ QSGTextInput::EchoMode echoMode = QSGTextInput::EchoMode(index);
+ textInput->setEchoMode(echoMode);
+ textInput->setText("My password");
+ textInput->select(0, textInput->text().length());;
+ textInput->copy();
+ if (echoMode == QSGTextInput::Normal) {
+ QVERIFY(!clipboard->text().isEmpty());
+ QCOMPARE(clipboard->text(), QString("My password"));
+ clipboard->clear();
+ } else {
+ QVERIFY(clipboard->text().isEmpty());
+ }
+ index++;
+ }
+
+ delete textInput;
+#endif
+}
+
+void tst_qsgtextinput::canPasteEmpty() {
+#ifndef QT_NO_CLIPBOARD
+
+ QApplication::clipboard()->clear();
+
+ QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\" }";
+ QDeclarativeComponent textInputComponent(&engine);
+ textInputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textInput = qobject_cast<QSGTextInput*>(textInputComponent.create());
+ QVERIFY(textInput != 0);
+
+ QLineControl lc;
+ bool cp = !lc.isReadOnly() && QApplication::clipboard()->text().length() != 0;
+ QCOMPARE(textInput->canPaste(), cp);
+
+#endif
+}
+
+void tst_qsgtextinput::canPaste() {
+#ifndef QT_NO_CLIPBOARD
+
+ QApplication::clipboard()->setText("Some text");
+
+ QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\" }";
+ QDeclarativeComponent textInputComponent(&engine);
+ textInputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textInput = qobject_cast<QSGTextInput*>(textInputComponent.create());
+ QVERIFY(textInput != 0);
+
+ QLineControl lc;
+ bool cp = !lc.isReadOnly() && QApplication::clipboard()->text().length() != 0;
+ QCOMPARE(textInput->canPaste(), cp);
+
+#endif
+}
+
+void tst_qsgtextinput::passwordCharacter()
+{
+ QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\"; font.family: \"Helvetica\"; echoMode: TextInput.Password }";
+ QDeclarativeComponent textInputComponent(&engine);
+ textInputComponent.setData(componentStr.toLatin1(), QUrl());
+ QSGTextInput *textInput = qobject_cast<QSGTextInput*>(textInputComponent.create());
+ QVERIFY(textInput != 0);
+
+ textInput->setPasswordCharacter("X");
+ QSize contentsSize = textInput->contentsSize();
+ qreal implicitWidth = textInput->implicitWidth();
+ textInput->setPasswordCharacter(".");
+
+ QEXPECT_FAIL("", "QSGPaintedItem::contentSize()/setContentSize() not implemented", Continue);
+ // QTBUG-12383 content is updated and redrawn
+ QVERIFY(contentsSize != textInput->contentsSize());
+ QVERIFY(textInput->implicitWidth() < implicitWidth);
+
+ delete textInput;
+}
+
+void tst_qsgtextinput::cursorDelegate()
+{
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/cursorTest.qml"));
+ view.show();
+ view.setFocus();
+ QSGTextInput *textInputObject = view.rootObject()->findChild<QSGTextInput*>("textInputObject");
+ QVERIFY(textInputObject != 0);
+ QVERIFY(textInputObject->findChild<QSGItem*>("cursorInstance"));
+ //Test Delegate gets created
+ textInputObject->setFocus(true);
+ QSGItem* delegateObject = textInputObject->findChild<QSGItem*>("cursorInstance");
+ QVERIFY(delegateObject);
+ //Test Delegate gets moved
+ for(int i=0; i<= textInputObject->text().length(); i++){
+ textInputObject->setCursorPosition(i);
+ QCOMPARE(textInputObject->cursorRectangle().x(), qRound(delegateObject->x()));
+ QCOMPARE(textInputObject->cursorRectangle().y(), qRound(delegateObject->y()));
+ }
+ textInputObject->setCursorPosition(0);
+ QCOMPARE(textInputObject->cursorRectangle().x(), qRound(delegateObject->x()));
+ QCOMPARE(textInputObject->cursorRectangle().y(), qRound(delegateObject->y()));
+ //Test Delegate gets deleted
+ textInputObject->setCursorDelegate(0);
+ QVERIFY(!textInputObject->findChild<QSGItem*>("cursorInstance"));
+}
+
+void tst_qsgtextinput::cursorVisible()
+{
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/cursorVisible.qml"));
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ view.setFocus();
+
+ QSGTextInput input;
+ QSignalSpy spy(&input, SIGNAL(cursorVisibleChanged(bool)));
+
+ QCOMPARE(input.isCursorVisible(), false);
+
+ input.setCursorVisible(true);
+ QCOMPARE(input.isCursorVisible(), true);
+ QCOMPARE(spy.count(), 1);
+
+ input.setCursorVisible(false);
+ QCOMPARE(input.isCursorVisible(), false);
+ QCOMPARE(spy.count(), 2);
+
+ input.setFocus(true);
+ QCOMPARE(input.isCursorVisible(), false);
+ QCOMPARE(spy.count(), 2);
+
+ input.setParentItem(view.rootObject());
+ QCOMPARE(input.isCursorVisible(), true);
+ QCOMPARE(spy.count(), 3);
+
+ input.setFocus(false);
+ QCOMPARE(input.isCursorVisible(), false);
+ QCOMPARE(spy.count(), 4);
+
+ input.setFocus(true);
+ QCOMPARE(input.isCursorVisible(), true);
+ QCOMPARE(spy.count(), 5);
+
+ view.clearFocus();
+ QCOMPARE(input.isCursorVisible(), false);
+ QCOMPARE(spy.count(), 6);
+
+ view.setFocus();
+ QCOMPARE(input.isCursorVisible(), true);
+ QCOMPARE(spy.count(), 7);
+
+ // on mac, setActiveWindow(0) on mac does not deactivate the current application
+ // (you have to switch to a different app or hide the current app to trigger this)
+#if !defined(Q_WS_MAC)
+ QApplication::setActiveWindow(0);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(0));
+ QCOMPARE(input.isCursorVisible(), false);
+ QCOMPARE(spy.count(), 8);
+
+ QApplication::setActiveWindow(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QCOMPARE(input.isCursorVisible(), true);
+ QCOMPARE(spy.count(), 9);
+#endif
+}
+
+void tst_qsgtextinput::cursorRectangle()
+{
+ QString text = "Hello World!";
+
+ QSGTextInput input;
+ input.setText(text);
+ QFontMetricsF fm(input.font());
+ input.setWidth(fm.width(text.mid(0, 5)));
+
+ QRect r;
+
+ // some tolerance for different fonts.
+#ifdef Q_OS_LINUX
+ const int error = 2;
+#else
+ const int error = 5;
+#endif
+
+
+ for (int i = 0; i <= 5; ++i) {
+ input.setCursorPosition(i);
+ r = input.cursorRectangle();
+ int textWidth = fm.width(text.mid(0, i));
+
+ QVERIFY(r.left() < textWidth + error);
+ QVERIFY(r.right() > textWidth - error);
+ QCOMPARE(input.inputMethodQuery(Qt::ImMicroFocus).toRect(), r);
+ }
+
+ // Check the cursor rectangle remains within the input bounding rect when auto scrolling.
+ QVERIFY(r.left() < input.boundingRect().width());
+ QVERIFY(r.right() >= input.width());
+
+ for (int i = 6; i < text.length(); ++i) {
+ input.setCursorPosition(i);
+ QCOMPARE(r, input.cursorRectangle());
+ QCOMPARE(input.inputMethodQuery(Qt::ImMicroFocus).toRect(), r);
+ }
+
+ for (int i = text.length() - 2; i >= 0; --i) {
+ input.setCursorPosition(i);
+ r = input.cursorRectangle();
+ QVERIFY(r.right() >= 0);
+ QCOMPARE(input.inputMethodQuery(Qt::ImMicroFocus).toRect(), r);
+ }
+}
+
+void tst_qsgtextinput::readOnly()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/readOnly.qml"));
+ canvas.show();
+ canvas.setFocus();
+
+ QVERIFY(canvas.rootObject() != 0);
+
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
+
+ QVERIFY(input != 0);
+ QTRY_VERIFY(input->hasActiveFocus() == true);
+ QVERIFY(input->isReadOnly() == true);
+ QString initial = input->text();
+ for(int k=Qt::Key_0; k<=Qt::Key_Z; k++)
+ simulateKey(&canvas, k);
+ simulateKey(&canvas, Qt::Key_Return);
+ simulateKey(&canvas, Qt::Key_Space);
+ simulateKey(&canvas, Qt::Key_Escape);
+ QCOMPARE(input->text(), initial);
+}
+
+void tst_qsgtextinput::echoMode()
+{
+ QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/echoMode.qml"));
+ canvas.show();
+ canvas.setFocus();
+ QApplication::setActiveWindow(&canvas);
+ QTest::qWaitForWindowShown(&canvas);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+
+ QVERIFY(canvas.rootObject() != 0);
+
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("myInput")));
+
+ QVERIFY(input != 0);
+ QTRY_VERIFY(input->hasActiveFocus() == true);
+ QString initial = input->text();
+ Qt::InputMethodHints ref;
+ QCOMPARE(initial, QLatin1String("ABCDefgh"));
+ QCOMPARE(input->echoMode(), QSGTextInput::Normal);
+ QCOMPARE(input->displayText(), input->text());
+ //Normal
+ ref &= ~Qt::ImhHiddenText;
+ ref &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ QCOMPARE(input->inputMethodHints(), ref);
+ input->setEchoMode(QSGTextInput::NoEcho);
+ QCOMPARE(input->text(), initial);
+ QCOMPARE(input->displayText(), QLatin1String(""));
+ QCOMPARE(input->passwordCharacter(), QLatin1String("*"));
+ //NoEcho
+ ref |= Qt::ImhHiddenText;
+ ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ QCOMPARE(input->inputMethodHints(), ref);
+ input->setEchoMode(QSGTextInput::Password);
+ //Password
+ ref |= Qt::ImhHiddenText;
+ ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ QCOMPARE(input->text(), initial);
+ QCOMPARE(input->displayText(), QLatin1String("********"));
+ QCOMPARE(input->inputMethodHints(), ref);
+ input->setPasswordCharacter(QChar('Q'));
+ QCOMPARE(input->passwordCharacter(), QLatin1String("Q"));
+ QCOMPARE(input->text(), initial);
+ QCOMPARE(input->displayText(), QLatin1String("QQQQQQQQ"));
+ input->setEchoMode(QSGTextInput::PasswordEchoOnEdit);
+ //PasswordEchoOnEdit
+ ref &= ~Qt::ImhHiddenText;
+ ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ QCOMPARE(input->inputMethodHints(), ref);
+ QCOMPARE(input->text(), initial);
+ QCOMPARE(input->displayText(), QLatin1String("QQQQQQQQ"));
+ QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("QQQQQQQQ"));
+ QTest::keyPress(&canvas, Qt::Key_A);//Clearing previous entry is part of PasswordEchoOnEdit
+ QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
+ QCOMPARE(input->text(), QLatin1String("a"));
+ QCOMPARE(input->displayText(), QLatin1String("a"));
+ QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("a"));
+ input->setFocus(false);
+ QVERIFY(input->hasActiveFocus() == false);
+ QCOMPARE(input->displayText(), QLatin1String("Q"));
+ QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("Q"));
+ input->setFocus(true);
+ QInputMethodEvent inputEvent;
+ inputEvent.setCommitString(initial);
+ QApplication::sendEvent(&canvas, &inputEvent);
+ QCOMPARE(input->text(), initial);
+ QCOMPARE(input->displayText(), initial);
+ QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), initial);
+}
+
+void tst_qsgtextinput::simulateKey(QSGView *view, int key)
+{
+ QKeyEvent press(QKeyEvent::KeyPress, key, 0);
+ QKeyEvent release(QKeyEvent::KeyRelease, key, 0);
+
+ QApplication::sendEvent(view, &press);
+ QApplication::sendEvent(view, &release);
+}
+
+class MyInputContext : public QInputContext
+{
+public:
+ MyInputContext() : openInputPanelReceived(false), closeInputPanelReceived(false), updateReceived(false), eventType(QEvent::None) {}
+ ~MyInputContext() {}
+
+ QString identifierName() { return QString(); }
+ QString language() { return QString(); }
+
+ void reset() {}
+
+ bool isComposing() const { return false; }
+
+ bool filterEvent( const QEvent *event )
+ {
+ if (event->type() == QEvent::RequestSoftwareInputPanel)
+ openInputPanelReceived = true;
+ if (event->type() == QEvent::CloseSoftwareInputPanel)
+ closeInputPanelReceived = true;
+ return QInputContext::filterEvent(event);
+ }
+
+ void update() { updateReceived = true; }
+
+ void mouseHandler(int x, QMouseEvent *event)
+ {
+ cursor = x;
+ eventType = event->type();
+ eventPosition = event->pos();
+ eventGlobalPosition = event->globalPos();
+ eventButton = event->button();
+ eventButtons = event->buttons();
+ eventModifiers = event->modifiers();
+ }
+
+ void sendPreeditText(const QString &text, int cursor)
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes.append(QInputMethodEvent::Attribute(
+ QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
+
+ QInputMethodEvent event(text, attributes);
+ sendEvent(event);
+ }
+
+ bool openInputPanelReceived;
+ bool closeInputPanelReceived;
+ bool updateReceived;
+ int cursor;
+ QEvent::Type eventType;
+ QPoint eventPosition;
+ QPoint eventGlobalPosition;
+ Qt::MouseButton eventButton;
+ Qt::MouseButtons eventButtons;
+ Qt::KeyboardModifiers eventModifiers;
+};
+
+void tst_qsgtextinput::openInputPanelOnClick()
+{
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/openInputPanel.qml"));
+ MyInputContext ic;
+ // QSGCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has focus
+ // and QWidget won't allow an input context to be set when the flag is not set.
+ view.setAttribute(Qt::WA_InputMethodEnabled, true);
+ view.setInputContext(&ic);
+ view.setAttribute(Qt::WA_InputMethodEnabled, false);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(view.rootObject());
+ QVERIFY(input);
+
+ QSGItemPrivate* pri = QSGItemPrivate::get(input);
+ QSGTextInputPrivate *inputPrivate = static_cast<QSGTextInputPrivate*>(pri);
+
+ // input panel on click
+ inputPrivate->showInputPanelOnFocus = false;
+
+ QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel(
+ view.style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
+ QTest::mouseClick(&view, Qt::LeftButton, 0, input->pos().toPoint());
+ QApplication::processEvents();
+ if (behavior == QStyle::RSIP_OnMouseClickAndAlreadyFocused) {
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QTest::mouseClick(&view, Qt::LeftButton, 0, input->pos().toPoint());
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, true);
+ } else if (behavior == QStyle::RSIP_OnMouseClick) {
+ QCOMPARE(ic.openInputPanelReceived, true);
+ }
+ ic.openInputPanelReceived = false;
+
+ // focus should not cause input panels to open or close
+ input->setFocus(false);
+ input->setFocus(true);
+ input->setFocus(false);
+ input->setFocus(true);
+ input->setFocus(false);
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QCOMPARE(ic.closeInputPanelReceived, false);
+}
+
+void tst_qsgtextinput::openInputPanelOnFocus()
+{
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/openInputPanel.qml"));
+ MyInputContext ic;
+ // QSGCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has focus
+ // and QWidget won't allow an input context to be set when the flag is not set.
+ view.setAttribute(Qt::WA_InputMethodEnabled, true);
+ view.setInputContext(&ic);
+ view.setAttribute(Qt::WA_InputMethodEnabled, false);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(view.rootObject());
+ QVERIFY(input);
+ QSignalSpy focusOnPressSpy(input, SIGNAL(activeFocusOnPressChanged(bool)));
+
+ QSGItemPrivate* pri = QSGItemPrivate::get(input);
+ QSGTextInputPrivate *inputPrivate = static_cast<QSGTextInputPrivate*>(pri);
+ inputPrivate->showInputPanelOnFocus = true;
+
+ // test default values
+ QVERIFY(input->focusOnPress());
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QCOMPARE(ic.closeInputPanelReceived, false);
+
+ // focus on press, input panel on focus
+ QTest::mousePress(&view, Qt::LeftButton, 0, input->pos().toPoint());
+ QApplication::processEvents();
+ QVERIFY(input->hasActiveFocus());
+ QCOMPARE(ic.openInputPanelReceived, true);
+ ic.openInputPanelReceived = false;
+
+ // no events on release
+ QTest::mouseRelease(&view, Qt::LeftButton, 0, input->pos().toPoint());
+ QCOMPARE(ic.openInputPanelReceived, false);
+ ic.openInputPanelReceived = false;
+
+ // if already focused, input panel can be opened on press
+ QVERIFY(input->hasActiveFocus());
+ QTest::mousePress(&view, Qt::LeftButton, 0, input->pos().toPoint());
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, true);
+ ic.openInputPanelReceived = false;
+
+ // input method should stay enabled if focus
+ // is lost to an item that also accepts inputs
+ QSGTextInput anotherInput;
+ anotherInput.setParentItem(view.rootItem());
+ anotherInput.setFocus(true);
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, true);
+ ic.openInputPanelReceived = false;
+ QCOMPARE(view.inputContext(), (QInputContext*)&ic);
+ QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // input method should be disabled if focus
+ // is lost to an item that doesn't accept inputs
+ QSGItem item;
+ item.setParentItem(view.rootItem());
+ item.setFocus(true);
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QVERIFY(view.inputContext() == 0);
+ QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // no automatic input panel events should
+ // be sent if activeFocusOnPress is false
+ input->setFocusOnPress(false);
+ QCOMPARE(focusOnPressSpy.count(),1);
+ input->setFocusOnPress(false);
+ QCOMPARE(focusOnPressSpy.count(),1);
+ input->setFocus(false);
+ input->setFocus(true);
+ QTest::mousePress(&view, Qt::LeftButton, 0, input->pos().toPoint());
+ QTest::mouseRelease(&view, Qt::LeftButton, 0, input->pos().toPoint());
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QCOMPARE(ic.closeInputPanelReceived, false);
+
+ // one show input panel event should
+ // be set when openSoftwareInputPanel is called
+ input->openSoftwareInputPanel();
+ QCOMPARE(ic.openInputPanelReceived, true);
+ QCOMPARE(ic.closeInputPanelReceived, false);
+ ic.openInputPanelReceived = false;
+
+ // one close input panel event should
+ // be sent when closeSoftwareInputPanel is called
+ input->closeSoftwareInputPanel();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QCOMPARE(ic.closeInputPanelReceived, true);
+ ic.closeInputPanelReceived = false;
+
+ // set activeFocusOnPress back to true
+ input->setFocusOnPress(true);
+ QCOMPARE(focusOnPressSpy.count(),2);
+ input->setFocusOnPress(true);
+ QCOMPARE(focusOnPressSpy.count(),2);
+ input->setFocus(false);
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QCOMPARE(ic.closeInputPanelReceived, false);
+ ic.closeInputPanelReceived = false;
+
+ // input panel should not re-open
+ // if focus has already been set
+ input->setFocus(true);
+ QCOMPARE(ic.openInputPanelReceived, true);
+ ic.openInputPanelReceived = false;
+ input->setFocus(true);
+ QCOMPARE(ic.openInputPanelReceived, false);
+
+ // input method should be disabled
+ // if TextInput loses focus
+ input->setFocus(false);
+ QApplication::processEvents();
+ QVERIFY(view.inputContext() == 0);
+ QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // input method should not be enabled
+ // if TextEdit is read only.
+ input->setReadOnly(true);
+ ic.openInputPanelReceived = false;
+ input->setFocus(true);
+ QApplication::processEvents();
+ QCOMPARE(ic.openInputPanelReceived, false);
+ QVERIFY(view.inputContext() == 0);
+ QVERIFY(!view.testAttribute(Qt::WA_InputMethodEnabled));
+}
+
+class MyTextInput : public QSGTextInput
+{
+public:
+ MyTextInput(QSGItem *parent = 0) : QSGTextInput(parent)
+ {
+ nbPaint = 0;
+ }
+ void paint(QPainter *painter)
+ {
+ nbPaint++;
+ QSGTextInput::paint(painter);
+ }
+ int nbPaint;
+};
+
+void tst_qsgtextinput::setHAlignClearCache()
+{
+ QSGView view;
+ MyTextInput input;
+ input.setText("Hello world");
+ input.setParentItem(view.rootItem());
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(input.nbPaint, 1);
+ input.setHAlign(QSGTextInput::AlignRight);
+ QApplication::processEvents();
+ //Changing the alignment should trigger a repaint
+ QCOMPARE(input.nbPaint, 2);
+}
+
+void tst_qsgtextinput::focusOutClearSelection()
+{
+ QSGView view;
+ QSGTextInput input;
+ QSGTextInput input2;
+ input.setText(QLatin1String("Hello world"));
+ input.setFocus(true);
+ input2.setParentItem(view.rootItem());
+ input.setParentItem(view.rootItem());
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ input.select(2,5);
+ //The selection should work
+ QTRY_COMPARE(input.selectedText(), QLatin1String("llo"));
+ input2.setFocus(true);
+ QApplication::processEvents();
+ //The input lost the focus selection should be cleared
+ QTRY_COMPARE(input.selectedText(), QLatin1String(""));
+}
+
+void tst_qsgtextinput::geometrySignals()
+{
+ QDeclarativeComponent component(&engine, SRCDIR "/data/geometrySignals.qml");
+ QObject *o = component.create();
+ QVERIFY(o);
+ QCOMPARE(o->property("bindingWidth").toInt(), 400);
+ QCOMPARE(o->property("bindingHeight").toInt(), 500);
+ delete o;
+}
+
+void tst_qsgtextinput::testQtQuick11Attributes()
+{
+ QFETCH(QString, code);
+ QFETCH(QString, warning);
+ QFETCH(QString, error);
+
+ QDeclarativeEngine engine;
+ QObject *obj;
+
+ QDeclarativeComponent valid(&engine);
+ valid.setData("import QtQuick 2.0; TextInput { " + code.toUtf8() + " }", QUrl(""));
+ obj = valid.create();
+ QVERIFY(obj);
+ QVERIFY(valid.errorString().isEmpty());
+ delete obj;
+
+ QDeclarativeComponent invalid(&engine);
+ invalid.setData("import QtQuick 1.0; TextInput { " + code.toUtf8() + " }", QUrl(""));
+ QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
+ obj = invalid.create();
+ QCOMPARE(invalid.errorString(), error);
+ delete obj;
+}
+
+void tst_qsgtextinput::testQtQuick11Attributes_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("canPaste") << "property bool foo: canPaste"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: canPaste"
+ << "";
+
+ QTest::newRow("moveCursorSelection") << "Component.onCompleted: moveCursorSelection(0, TextEdit.SelectCharacters)"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: moveCursorSelection"
+ << "";
+
+ QTest::newRow("deselect") << "Component.onCompleted: deselect()"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: deselect"
+ << "";
+}
+
+void tst_qsgtextinput::preeditAutoScroll()
+{
+ QString preeditText = "califragisiticexpialidocious!";
+
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/preeditAutoScroll.qml"));
+ MyInputContext ic;
+ view.setInputContext(&ic);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(view.rootObject());
+ QVERIFY(input);
+
+ QFontMetricsF fm(input->font());
+ input->setWidth(fm.width(input->text()));
+
+ // test the text is scrolled so the preedit is visible.
+ ic.sendPreeditText(preeditText.mid(0, 3), 1);
+ QVERIFY(input->positionAt(0) != 0);
+ QVERIFY(input->cursorRectangle().left() < input->boundingRect().width());
+
+ // test the text is scrolled back when the preedit is removed.
+ ic.sendEvent(QInputMethodEvent());
+ QCOMPARE(input->positionAt(0), 0);
+ QCOMPARE(input->positionAt(input->width()), 5);
+
+ // test if the preedit is larger than the text input that the
+ // character preceding the cursor is still visible.
+ qreal x = input->positionToRectangle(0).x();
+ for (int i = 0; i < 3; ++i) {
+ ic.sendPreeditText(preeditText, i + 1);
+ QVERIFY(input->cursorRectangle().right() >= fm.width(preeditText.at(i)));
+ QVERIFY(input->positionToRectangle(0).x() < x);
+ x = input->positionToRectangle(0).x();
+ }
+ for (int i = 1; i >= 0; --i) {
+ ic.sendPreeditText(preeditText, i + 1);
+ QVERIFY(input->cursorRectangle().right() >= fm.width(preeditText.at(i)));
+ QVERIFY(input->positionToRectangle(0).x() > x);
+ x = input->positionToRectangle(0).x();
+ }
+
+ // Test incrementing the preedit cursor doesn't cause further
+ // scrolling when right most text is visible.
+ ic.sendPreeditText(preeditText, preeditText.length() - 3);
+ x = input->positionToRectangle(0).x();
+ for (int i = 2; i >= 0; --i) {
+ ic.sendPreeditText(preeditText, preeditText.length() - i);
+ QCOMPARE(input->positionToRectangle(0).x(), x);
+ }
+ for (int i = 1; i < 3; ++i) {
+ ic.sendPreeditText(preeditText, preeditText.length() - i);
+ QCOMPARE(input->positionToRectangle(0).x(), x);
+ }
+
+ // Test disabling auto scroll.
+ ic.sendEvent(QInputMethodEvent());
+
+ input->setAutoScroll(false);
+ ic.sendPreeditText(preeditText.mid(0, 3), 1);
+ QCOMPARE(input->positionAt(0), 0);
+ QCOMPARE(input->positionAt(input->width()), 5);
+}
+
+void tst_qsgtextinput::preeditMicroFocus()
+{
+ QString preeditText = "super";
+
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/inputMethodEvent.qml"));
+ MyInputContext ic;
+ view.setInputContext(&ic);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(view.rootObject());
+ QVERIFY(input);
+
+ QRect currentRect;
+ QRect previousRect = input->inputMethodQuery(Qt::ImMicroFocus).toRect();
+
+ // Verify that the micro focus rect is positioned the same for position 0 as
+ // it would be if there was no preedit text.
+ ic.updateReceived = false;
+ ic.sendPreeditText(preeditText, 0);
+ currentRect = input->inputMethodQuery(Qt::ImMicroFocus).toRect();
+ QCOMPARE(currentRect, previousRect);
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+ QCOMPARE(ic.updateReceived, true);
+#endif
+
+ // Verify that the micro focus rect moves to the left as the cursor position
+ // is incremented.
+ for (int i = 1; i <= 5; ++i) {
+ ic.updateReceived = false;
+ ic.sendPreeditText(preeditText, i);
+ currentRect = input->inputMethodQuery(Qt::ImMicroFocus).toRect();
+ QVERIFY(previousRect.left() < currentRect.left());
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+ QCOMPARE(ic.updateReceived, true);
+#endif
+ previousRect = currentRect;
+ }
+
+ // Verify that if there is no preedit cursor then the micro focus rect is the
+ // same as it would be if it were positioned at the end of the preedit text.
+ ic.sendPreeditText(preeditText, 0);
+ ic.updateReceived = false;
+ ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>()));
+ currentRect = input->inputMethodQuery(Qt::ImMicroFocus).toRect();
+ QCOMPARE(currentRect, previousRect);
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
+ QCOMPARE(ic.updateReceived, true);
+#endif
+}
+
+void tst_qsgtextinput::inputContextMouseHandler()
+{
+ QString text = "supercalifragisiticexpialidocious!";
+
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/inputContext.qml"));
+ MyInputContext ic;
+ view.setInputContext(&ic);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(view.rootObject());
+ QVERIFY(input);
+
+ QFontMetricsF fm(input->font());
+ const qreal y = fm.height() / 2;
+
+ QPoint position2 = input->mapToScene(QPointF(fm.width(text.mid(0, 2)), y)).toPoint();
+ QPoint position8 = input->mapToScene(QPointF(fm.width(text.mid(0, 8)), y)).toPoint();
+ QPoint position20 = input->mapToScene(QPointF(fm.width(text.mid(0, 20)), y)).toPoint();
+ QPoint position27 = input->mapToScene(QPointF(fm.width(text.mid(0, 27)), y)).toPoint();
+ QPoint globalPosition2 = view.mapToGlobal(position2);
+ QPoint globalposition8 = view.mapToGlobal(position8);
+ QPoint globalposition20 = view.mapToGlobal(position20);
+ QPoint globalposition27 = view.mapToGlobal(position27);
+
+ ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>()));
+
+ QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, position2);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
+ QCOMPARE(ic.eventPosition, position2);
+ QCOMPARE(ic.eventGlobalPosition, globalPosition2);
+ QCOMPARE(ic.eventButton, Qt::LeftButton);
+ QCOMPARE(ic.eventModifiers, Qt::NoModifier);
+ QVERIFY(ic.cursor < 0);
+ ic.eventType = QEvent::None;
+
+ QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position2);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
+ QCOMPARE(ic.eventPosition, position2);
+ QCOMPARE(ic.eventGlobalPosition, globalPosition2);
+ QCOMPARE(ic.eventButton, Qt::LeftButton);
+ QCOMPARE(ic.eventModifiers, Qt::NoModifier);
+ QVERIFY(ic.cursor < 0);
+ ic.eventType = QEvent::None;
+
+ { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&view, &mv); }
+ QCOMPARE(ic.eventType, QEvent::None);
+
+ { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(&view, &mv); }
+ QCOMPARE(ic.eventType, QEvent::MouseMove);
+ QCOMPARE(ic.eventPosition, position27);
+ QCOMPARE(ic.eventGlobalPosition, globalposition27);
+ QCOMPARE(ic.eventButton, Qt::LeftButton);
+ QCOMPARE(ic.eventModifiers, Qt::NoModifier);
+ QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); // 15 is expected but some platforms may be off by one.
+ ic.eventType = QEvent::None;
+
+ QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position27);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
+ QCOMPARE(ic.eventPosition, position27);
+ QCOMPARE(ic.eventGlobalPosition, globalposition27);
+ QCOMPARE(ic.eventButton, Qt::LeftButton);
+ QCOMPARE(ic.eventModifiers, Qt::NoModifier);
+ QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
+ ic.eventType = QEvent::None;
+
+ // And in the other direction.
+ QTest::mouseDClick(&view, Qt::LeftButton, Qt::ControlModifier, position27);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick);
+ QCOMPARE(ic.eventPosition, position27);
+ QCOMPARE(ic.eventGlobalPosition, globalposition27);
+ QCOMPARE(ic.eventButton, Qt::LeftButton);
+ QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
+ QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
+ ic.eventType = QEvent::None;
+
+ QTest::mousePress(&view, Qt::RightButton, Qt::ControlModifier, position27);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonPress);
+ QCOMPARE(ic.eventPosition, position27);
+ QCOMPARE(ic.eventGlobalPosition, globalposition27);
+ QCOMPARE(ic.eventButton, Qt::RightButton);
+ QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
+ QVERIFY(ic.cursor >= 14 && ic.cursor <= 16);
+ ic.eventType = QEvent::None;
+
+ { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
+ QApplication::sendEvent(&view, &mv); }
+ QCOMPARE(ic.eventType, QEvent::MouseMove);
+ QCOMPARE(ic.eventPosition, position20);
+ QCOMPARE(ic.eventGlobalPosition, globalposition20);
+ QCOMPARE(ic.eventButton, Qt::RightButton);
+ QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
+ QVERIFY(ic.cursor >= 7 && ic.cursor <= 9);
+ ic.eventType = QEvent::None;
+
+ { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier);
+ QApplication::sendEvent(&view, &mv); }
+ QCOMPARE(ic.eventType, QEvent::None);
+
+ QTest::mouseRelease(&view, Qt::RightButton, Qt::ControlModifier, position2);
+ QCOMPARE(ic.eventType, QEvent::MouseButtonRelease);
+ QCOMPARE(ic.eventPosition, position2);
+ QCOMPARE(ic.eventGlobalPosition, globalPosition2);
+ QCOMPARE(ic.eventButton, Qt::RightButton);
+ QCOMPARE(ic.eventModifiers, Qt::ControlModifier);
+ QVERIFY(ic.cursor < 0);
+ ic.eventType = QEvent::None;
+}
+
+void tst_qsgtextinput::inputMethodComposing()
+{
+ QString text = "supercalifragisiticexpialidocious!";
+
+ QSGView view(QUrl::fromLocalFile(SRCDIR "/data/inputContext.qml"));
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+ QSGTextInput *input = qobject_cast<QSGTextInput *>(view.rootObject());
+ QVERIFY(input);
+ QSignalSpy spy(input, SIGNAL(inputMethodComposingChanged()));
+
+ QCOMPARE(input->isInputMethodComposing(), false);
+ {
+ QInputMethodEvent event(text.mid(3), QList<QInputMethodEvent::Attribute>());
+ QApplication::sendEvent(&view, &event);
+ }
+ QCOMPARE(input->isInputMethodComposing(), true);
+ QCOMPARE(spy.count(), 1);
+
+ {
+ QInputMethodEvent event(text.mid(12), QList<QInputMethodEvent::Attribute>());
+ QApplication::sendEvent(&view, &event);
+ }
+ QCOMPARE(spy.count(), 1);
+
+ {
+ QInputMethodEvent event;
+ QApplication::sendEvent(&view, &event);
+ }
+ QCOMPARE(input->isInputMethodComposing(), false);
+ QCOMPARE(spy.count(), 2);
+}
+
+void tst_qsgtextinput::cursorRectangleSize()
+{
+ QSGView *canvas = new QSGView(QUrl::fromLocalFile(SRCDIR "/data/positionAt.qml"));
+ QVERIFY(canvas->rootObject() != 0);
+ canvas->show();
+ canvas->setFocus();
+ QApplication::setActiveWindow(canvas);
+ QTest::qWaitForWindowShown(canvas);
+
+ QSGTextInput *textInput = qobject_cast<QSGTextInput *>(canvas->rootObject());
+ QVERIFY(textInput != 0);
+ textInput->setFocus(Qt::OtherFocusReason);
+ QRectF cursorRect = textInput->positionToRectangle(textInput->cursorPosition());
+ QRectF microFocusFromScene = canvas->inputMethodQuery(Qt::ImMicroFocus).toRectF();
+ QRectF microFocusFromApp= QApplication::focusWidget()->inputMethodQuery(Qt::ImMicroFocus).toRectF();
+
+ QCOMPARE(microFocusFromScene.size(), cursorRect.size());
+ QCOMPARE(microFocusFromApp.size(), cursorRect.size());
+
+ delete canvas;
+}
+
+QTEST_MAIN(tst_qsgtextinput)
+
+#include "tst_qsgtextinput.moc"
diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/datalist.qml b/tests/auto/declarative/qsgvisualdatamodel/data/datalist.qml
new file mode 100644
index 0000000000..8ce59caddc
--- /dev/null
+++ b/tests/auto/declarative/qsgvisualdatamodel/data/datalist.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+ model: VisualDataModel {
+ id: visualModel
+ objectName: "visualModel"
+ model: myModel
+ delegate: Component {
+ Rectangle {
+ height: 25
+ width: 100
+ Text { objectName: "display"; text: display }
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties.qml b/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties.qml
new file mode 100644
index 0000000000..6d86cdea2e
--- /dev/null
+++ b/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+ model: myModel
+ delegate: Item {
+ objectName: "delegate"
+ property variant test1: name
+ property variant test2: model.name
+ property variant test3: modelData
+ property variant test4: model.modelData
+ property variant test5: modelData.name
+ property variant test6: model
+ property variant test7: index
+ property variant test8: model.index
+ property variant test9: model.modelData.name
+ }
+}
diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties2.qml b/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties2.qml
new file mode 100644
index 0000000000..6a92431cdf
--- /dev/null
+++ b/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties2.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+ model: myModel
+ delegate: Item {
+ objectName: "delegate"
+ property variant test1: display
+ property variant test2: model.display
+ property variant test3: modelData
+ property variant test4: model.modelData
+ property variant test5: modelData.display
+ property variant test6: model
+ property variant test7: index
+ property variant test8: model.index
+ property variant test9: model.modelData.display
+ }
+}
diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/objectlist.qml b/tests/auto/declarative/qsgvisualdatamodel/data/objectlist.qml
new file mode 100644
index 0000000000..9086e5ab57
--- /dev/null
+++ b/tests/auto/declarative/qsgvisualdatamodel/data/objectlist.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+ anchors.fill: parent
+ model: myModel
+ delegate: Component {
+ Rectangle {
+ height: 25
+ width: 100
+ color: model.modelData.color
+ Text { objectName: "name"; text: name }
+ Text { objectName: "section"; text: parent.ListView.section }
+ }
+ }
+ section.property: "name"
+ section.criteria: ViewSection.FullString
+}
diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/singlerole1.qml b/tests/auto/declarative/qsgvisualdatamodel/data/singlerole1.qml
new file mode 100644
index 0000000000..d5b0fcf09b
--- /dev/null
+++ b/tests/auto/declarative/qsgvisualdatamodel/data/singlerole1.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+ model: myModel
+ delegate: Component {
+ Text { objectName: "name"; text: name }
+ }
+}
diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/singlerole2.qml b/tests/auto/declarative/qsgvisualdatamodel/data/singlerole2.qml
new file mode 100644
index 0000000000..c6d3413dfd
--- /dev/null
+++ b/tests/auto/declarative/qsgvisualdatamodel/data/singlerole2.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+ model: myModel
+ delegate: Component {
+ Text { objectName: "name"; text: modelData }
+ }
+}
diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/visualdatamodel.qml b/tests/auto/declarative/qsgvisualdatamodel/data/visualdatamodel.qml
new file mode 100644
index 0000000000..0bb5cd13e0
--- /dev/null
+++ b/tests/auto/declarative/qsgvisualdatamodel/data/visualdatamodel.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+VisualDataModel {
+ function setRoot() {
+ rootIndex = modelIndex(0);
+ }
+ function setRootToParent() {
+ rootIndex = parentModelIndex();
+ }
+ model: myModel
+}
diff --git a/tests/auto/declarative/qsgvisualdatamodel/qsgvisualdatamodel.pro b/tests/auto/declarative/qsgvisualdatamodel/qsgvisualdatamodel.pro
new file mode 100644
index 0000000000..7d0df4dc7b
--- /dev/null
+++ b/tests/auto/declarative/qsgvisualdatamodel/qsgvisualdatamodel.pro
@@ -0,0 +1,16 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative gui
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qsgvisualdatamodel.cpp
+
+symbian: {
+ importFiles.files = data
+ importFiles.path = .
+ DEPLOYMENT += importFiles
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp
new file mode 100644
index 0000000000..23e629538d
--- /dev/null
+++ b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp
@@ -0,0 +1,531 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtTest/QSignalSpy>
+#include <QStandardItemModel>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qsgview.h>
+#include <private/qsglistview_p.h>
+#include <private/qsgtext_p.h>
+#include <private/qsgvisualitemmodel_p.h>
+#include <private/qdeclarativevaluetype_p.h>
+#include <math.h>
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+static void initStandardTreeModel(QStandardItemModel *model)
+{
+ QStandardItem *item;
+ item = new QStandardItem(QLatin1String("Row 1 Item"));
+ model->insertRow(0, item);
+
+ item = new QStandardItem(QLatin1String("Row 2 Item"));
+ item->setCheckable(true);
+ model->insertRow(1, item);
+
+ QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
+ item->setChild(0, childItem);
+
+ item = new QStandardItem(QLatin1String("Row 3 Item"));
+ item->setIcon(QIcon());
+ model->insertRow(2, item);
+}
+
+class SingleRoleModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ SingleRoleModel(QObject *parent = 0) {
+ QHash<int, QByteArray> roles;
+ roles.insert(Qt::DisplayRole , "name");
+ setRoleNames(roles);
+ list << "one" << "two" << "three" << "four";
+ }
+
+public slots:
+ void set(int idx, QString string) {
+ list[idx] = string;
+ emit dataChanged(index(idx,0), index(idx,0));
+ }
+
+protected:
+ int rowCount(const QModelIndex &parent = QModelIndex()) const {
+ return list.count();
+ }
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const {
+ if (role == Qt::DisplayRole)
+ return list.at(index.row());
+ return QVariant();
+ }
+
+private:
+ QStringList list;
+};
+
+
+class tst_qsgvisualdatamodel : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qsgvisualdatamodel();
+
+private slots:
+ void rootIndex();
+ void updateLayout();
+ void childChanged();
+ void objectListModel();
+ void singleRole();
+ void modelProperties();
+ void noDelegate();
+
+private:
+ QDeclarativeEngine engine;
+ template<typename T>
+ T *findItem(QSGItem *parent, const QString &objectName, int index);
+};
+
+class DataObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
+
+public:
+ DataObject(QObject *parent=0) : QObject(parent) {}
+ DataObject(const QString &name, const QString &color, QObject *parent=0)
+ : QObject(parent), m_name(name), m_color(color) { }
+
+
+ QString name() const { return m_name; }
+ void setName(const QString &name) {
+ if (name != m_name) {
+ m_name = name;
+ emit nameChanged();
+ }
+ }
+
+ QString color() const { return m_color; }
+ void setColor(const QString &color) {
+ if (color != m_color) {
+ m_color = color;
+ emit colorChanged();
+ }
+ }
+
+signals:
+ void nameChanged();
+ void colorChanged();
+
+private:
+ QString m_name;
+ QString m_color;
+};
+
+tst_qsgvisualdatamodel::tst_qsgvisualdatamodel()
+{
+}
+
+void tst_qsgvisualdatamodel::rootIndex()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/visualdatamodel.qml"));
+
+ QStandardItemModel model;
+ initStandardTreeModel(&model);
+
+ engine.rootContext()->setContextProperty("myModel", &model);
+
+ QSGVisualDataModel *obj = qobject_cast<QSGVisualDataModel*>(c.create());
+ QVERIFY(obj != 0);
+
+ QMetaObject::invokeMethod(obj, "setRoot");
+ QVERIFY(qvariant_cast<QModelIndex>(obj->rootIndex()) == model.index(0,0));
+
+ QMetaObject::invokeMethod(obj, "setRootToParent");
+ QVERIFY(qvariant_cast<QModelIndex>(obj->rootIndex()) == QModelIndex());
+
+ delete obj;
+}
+
+void tst_qsgvisualdatamodel::updateLayout()
+{
+ QSGView view;
+
+ QStandardItemModel model;
+ initStandardTreeModel(&model);
+
+ view.rootContext()->setContextProperty("myModel", &model);
+
+ view.setSource(QUrl::fromLocalFile(SRCDIR "/data/datalist.qml"));
+
+ QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
+ QVERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ QSGText *name = findItem<QSGText>(contentItem, "display", 0);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 1 Item"));
+ name = findItem<QSGText>(contentItem, "display", 1);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 2 Item"));
+ name = findItem<QSGText>(contentItem, "display", 2);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 3 Item"));
+
+ model.invisibleRootItem()->sortChildren(0, Qt::DescendingOrder);
+
+ name = findItem<QSGText>(contentItem, "display", 0);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 3 Item"));
+ name = findItem<QSGText>(contentItem, "display", 1);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 2 Item"));
+ name = findItem<QSGText>(contentItem, "display", 2);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 1 Item"));
+}
+
+void tst_qsgvisualdatamodel::childChanged()
+{
+ QSGView view;
+
+ QStandardItemModel model;
+ initStandardTreeModel(&model);
+
+ view.rootContext()->setContextProperty("myModel", &model);
+
+ view.setSource(QUrl::fromLocalFile(SRCDIR "/data/datalist.qml"));
+
+ QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
+ QVERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ QSGVisualDataModel *vdm = listview->findChild<QSGVisualDataModel*>("visualModel");
+ vdm->setRootIndex(QVariant::fromValue(model.indexFromItem(model.item(1,0))));
+
+ QSGText *name = findItem<QSGText>(contentItem, "display", 0);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 2 Child Item"));
+
+ model.item(1,0)->child(0,0)->setText("Row 2 updated child");
+
+ name = findItem<QSGText>(contentItem, "display", 0);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 2 updated child"));
+
+ model.item(1,0)->appendRow(new QStandardItem(QLatin1String("Row 2 Child Item 2")));
+ QTest::qWait(300);
+
+ name = findItem<QSGText>(contentItem, "display", 1);
+ QVERIFY(name != 0);
+ QCOMPARE(name->text(), QString("Row 2 Child Item 2"));
+
+ model.item(1,0)->takeRow(1);
+ name = findItem<QSGText>(contentItem, "display", 1);
+ QVERIFY(name == 0);
+
+ vdm->setRootIndex(QVariant::fromValue(QModelIndex()));
+ QTest::qWait(300);
+ name = findItem<QSGText>(contentItem, "display", 0);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 1 Item"));
+ name = findItem<QSGText>(contentItem, "display", 1);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 2 Item"));
+ name = findItem<QSGText>(contentItem, "display", 2);
+ QVERIFY(name);
+ QCOMPARE(name->text(), QString("Row 3 Item"));
+}
+
+void tst_qsgvisualdatamodel::objectListModel()
+{
+ QSGView view;
+
+ QList<QObject*> dataList;
+ dataList.append(new DataObject("Item 1", "red"));
+ dataList.append(new DataObject("Item 2", "green"));
+ dataList.append(new DataObject("Item 3", "blue"));
+ dataList.append(new DataObject("Item 4", "yellow"));
+
+ QDeclarativeContext *ctxt = view.rootContext();
+ ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
+
+ view.setSource(QUrl::fromLocalFile(SRCDIR "/data/objectlist.qml"));
+
+ QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
+ QVERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ QSGText *name = findItem<QSGText>(contentItem, "name", 0);
+ QCOMPARE(name->text(), QString("Item 1"));
+
+ QSGText *section = findItem<QSGText>(contentItem, "section", 0);
+ QCOMPARE(section->text(), QString("Item 1"));
+
+ dataList[0]->setProperty("name", QLatin1String("Changed"));
+ QCOMPARE(name->text(), QString("Changed"));
+}
+
+void tst_qsgvisualdatamodel::singleRole()
+{
+ {
+ QSGView view;
+
+ SingleRoleModel model;
+
+ QDeclarativeContext *ctxt = view.rootContext();
+ ctxt->setContextProperty("myModel", &model);
+
+ view.setSource(QUrl::fromLocalFile(SRCDIR "/data/singlerole1.qml"));
+
+ QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
+ QVERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ QSGText *name = findItem<QSGText>(contentItem, "name", 1);
+ QCOMPARE(name->text(), QString("two"));
+
+ model.set(1, "Changed");
+ QCOMPARE(name->text(), QString("Changed"));
+ }
+ {
+ QSGView view;
+
+ SingleRoleModel model;
+
+ QDeclarativeContext *ctxt = view.rootContext();
+ ctxt->setContextProperty("myModel", &model);
+
+ view.setSource(QUrl::fromLocalFile(SRCDIR "/data/singlerole2.qml"));
+
+ QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
+ QVERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ QSGText *name = findItem<QSGText>(contentItem, "name", 1);
+ QCOMPARE(name->text(), QString("two"));
+
+ model.set(1, "Changed");
+ QCOMPARE(name->text(), QString("Changed"));
+ }
+}
+
+void tst_qsgvisualdatamodel::modelProperties()
+{
+ {
+ QSGView view;
+
+ SingleRoleModel model;
+
+ QDeclarativeContext *ctxt = view.rootContext();
+ ctxt->setContextProperty("myModel", &model);
+
+ view.setSource(QUrl::fromLocalFile(SRCDIR "/data/modelproperties.qml"));
+
+ QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
+ QVERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", 1);
+ QVERIFY(delegate);
+ QCOMPARE(delegate->property("test1").toString(),QString("two"));
+ QCOMPARE(delegate->property("test2").toString(),QString("two"));
+ QCOMPARE(delegate->property("test3").toString(),QString("two"));
+ QCOMPARE(delegate->property("test4").toString(),QString("two"));
+ QVERIFY(!delegate->property("test9").isValid());
+ QCOMPARE(delegate->property("test5").toString(),QString(""));
+ QVERIFY(delegate->property("test6").value<QObject*>() != 0);
+ QCOMPARE(delegate->property("test7").toInt(),1);
+ QCOMPARE(delegate->property("test8").toInt(),1);
+ }
+
+ {
+ QSGView view;
+
+ QList<QObject*> dataList;
+ dataList.append(new DataObject("Item 1", "red"));
+ dataList.append(new DataObject("Item 2", "green"));
+ dataList.append(new DataObject("Item 3", "blue"));
+ dataList.append(new DataObject("Item 4", "yellow"));
+
+ QDeclarativeContext *ctxt = view.rootContext();
+ ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
+
+ view.setSource(QUrl::fromLocalFile(SRCDIR "/data/modelproperties.qml"));
+
+ QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
+ QVERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", 1);
+ QVERIFY(delegate);
+ QCOMPARE(delegate->property("test1").toString(),QString("Item 2"));
+ QEXPECT_FAIL("", "QTBUG-13576", Continue);
+ QCOMPARE(delegate->property("test2").toString(),QString("Item 2"));
+ QVERIFY(qobject_cast<DataObject*>(delegate->property("test3").value<QObject*>()) != 0);
+ QVERIFY(qobject_cast<DataObject*>(delegate->property("test4").value<QObject*>()) != 0);
+ QCOMPARE(delegate->property("test5").toString(),QString("Item 2"));
+ QCOMPARE(delegate->property("test9").toString(),QString("Item 2"));
+ QVERIFY(delegate->property("test6").value<QObject*>() != 0);
+ QCOMPARE(delegate->property("test7").toInt(),1);
+ QCOMPARE(delegate->property("test8").toInt(),1);
+ }
+
+ {
+ QSGView view;
+
+ QStandardItemModel model;
+ initStandardTreeModel(&model);
+
+ view.rootContext()->setContextProperty("myModel", &model);
+
+ QUrl source(QUrl::fromLocalFile(SRCDIR "/data/modelproperties2.qml"));
+
+ //3 items, 3 warnings each
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: Can't find variable: modelData");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: Can't find variable: modelData");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: Can't find variable: modelData");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: Can't find variable: modelData");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: Can't find variable: modelData");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: Can't find variable: modelData");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Result of expression 'model.modelData' [undefined] is not an object.");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Result of expression 'model.modelData' [undefined] is not an object.");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Result of expression 'model.modelData' [undefined] is not an object.");
+
+ view.setSource(source);
+
+ QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
+ QVERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", 1);
+ QVERIFY(delegate);
+ QCOMPARE(delegate->property("test1").toString(),QString("Row 2 Item"));
+ QCOMPARE(delegate->property("test2").toString(),QString("Row 2 Item"));
+ QVERIFY(!delegate->property("test3").isValid());
+ QVERIFY(!delegate->property("test4").isValid());
+ QVERIFY(!delegate->property("test5").isValid());
+ QVERIFY(!delegate->property("test9").isValid());
+ QVERIFY(delegate->property("test6").value<QObject*>() != 0);
+ QCOMPARE(delegate->property("test7").toInt(),1);
+ QCOMPARE(delegate->property("test8").toInt(),1);
+ }
+
+ //### should also test QStringList and QVariantList
+}
+
+void tst_qsgvisualdatamodel::noDelegate()
+{
+ QSGView view;
+
+ QStandardItemModel model;
+ initStandardTreeModel(&model);
+
+ view.rootContext()->setContextProperty("myModel", &model);
+
+ view.setSource(QUrl::fromLocalFile(SRCDIR "/data/datalist.qml"));
+
+ QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
+ QVERIFY(listview != 0);
+
+ QSGVisualDataModel *vdm = listview->findChild<QSGVisualDataModel*>("visualModel");
+ QVERIFY(vdm != 0);
+ QCOMPARE(vdm->count(), 3);
+
+ vdm->setDelegate(0);
+ QCOMPARE(vdm->count(), 0);
+}
+
+
+template<typename T>
+T *tst_qsgvisualdatamodel::findItem(QSGItem *parent, const QString &objectName, int index)
+{
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->childItems().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
+ if(!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ if (index != -1) {
+ QDeclarativeExpression e(qmlContext(item), item, "index");
+ if (e.evaluate().toInt() == index)
+ return static_cast<T*>(item);
+ } else {
+ return static_cast<T*>(item);
+ }
+ }
+ item = findItem<T>(item, objectName, index);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+}
+
+QTEST_MAIN(tst_qsgvisualdatamodel)
+
+#include "tst_qsgvisualdatamodel.moc"
diff --git a/tests/benchmarks/declarative/declarative.pro b/tests/benchmarks/declarative/declarative.pro
index cb02a35c27..a827978d63 100644
--- a/tests/benchmarks/declarative/declarative.pro
+++ b/tests/benchmarks/declarative/declarative.pro
@@ -3,6 +3,7 @@ TEMPLATE = subdirs
SUBDIRS += \
binding \
creation \
+ holistic \
pointers \
qdeclarativecomponent \
qdeclarativeimage \
diff --git a/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicFour.qml b/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicFour.qml
new file mode 100644
index 0000000000..81a666bf47
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicFour.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Item {
+ id: root
+ property int dynamicWidth: 100
+ property int dynamicHeight: rect1.height + rect2.height
+ property int widthSignaledProperty: 10
+ property int heightSignaledProperty: 10
+
+ Rectangle {
+ id: rect1
+ width: root.dynamicWidth + 20
+ height: width + (5*3) - 8 + (width/9)
+ color: "red"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+
+ Rectangle {
+ id: rect2
+ width: rect1.width - 50
+ height: width + (5*4) - 6 + (width/3)
+ color: "red"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+
+ onDynamicWidthChanged: {
+ widthSignaledProperty = widthSignaledProperty + (6*5) - 2;
+ }
+
+ onDynamicHeightChanged: {
+ heightSignaledProperty = widthSignaledProperty + heightSignaledProperty + (5*3) - 7;
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicOne.qml b/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicOne.qml
new file mode 100644
index 0000000000..6e726b12d4
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicOne.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Item {
+ id: root
+ property int dynamicWidth: 10
+
+ Rectangle {
+ width: 100
+ height: root.dynamicWidth + (5*3) - 8 + (root.dynamicWidth/10)
+ color: "red"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicThree.qml b/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicThree.qml
new file mode 100644
index 0000000000..19000d78fa
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicThree.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Item {
+ id: root
+ property int dynamicWidth: 10
+ property int widthSignaledProperty: 20
+
+ Rectangle {
+ width: 100
+ height: root.dynamicWidth + (5*3) - 8 + (root.dynamicWidth/10)
+ color: "red"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+
+ onDynamicWidthChanged: {
+ widthSignaledProperty = dynamicWidth + (20/4) + 7 - 1;
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicTwo.qml b/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicTwo.qml
new file mode 100644
index 0000000000..4f7340589b
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/dynamicTargets/DynamicTwo.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Item {
+ id: root
+ property int dynamicWidth: 100
+ property int dynamicHeight: rect1.height + rect2.height
+
+ Rectangle {
+ id: rect1
+ width: root.dynamicWidth + 20
+ height: width + (5*3) - 8 + (width/9)
+ color: "red"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+
+ Rectangle {
+ id: rect2
+ width: rect1.width - 50
+ height: width + (5*4) - 6 + (width/3)
+ color: "red"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/Mlbsi.qml b/tests/benchmarks/declarative/holistic/data/jsImports/Mlbsi.qml
new file mode 100644
index 0000000000..2ce9728d6a
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/Mlbsi.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "mlbsi.js" as MlbsiJs
+
+Item {
+ id: testQtObject
+ property int importedScriptFunctionValue: MlbsiJs.testFunc(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/Mldsi.qml b/tests/benchmarks/declarative/holistic/data/jsImports/Mldsi.qml
new file mode 100644
index 0000000000..c4455a46dc
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/Mldsi.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "mldsi.js" as MldsiJs
+
+Item {
+ id: testQtObject
+ property int importedScriptFunctionValue: MldsiJs.testFunc(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/Mlsi.qml b/tests/benchmarks/declarative/holistic/data/jsImports/Mlsi.qml
new file mode 100644
index 0000000000..99bb222e7a
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/Mlsi.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "mlsi.js" as MlsiJs
+
+Item {
+ id: testQtObject
+ property int importedScriptFunctionValue: MlsiJs.testFunc(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/ModuleBm.qml b/tests/benchmarks/declarative/holistic/data/jsImports/ModuleBm.qml
new file mode 100644
index 0000000000..bdae3564fc
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/ModuleBm.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "moduleBm.js" as ModuleBmJs
+
+Item {
+ id: testQtObject
+ property int importedScriptFunctionValue: ModuleBmJs.testFunc(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/Msbsi.qml b/tests/benchmarks/declarative/holistic/data/jsImports/Msbsi.qml
new file mode 100644
index 0000000000..05026cbf71
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/Msbsi.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "msbsi.js" as MsbsiJs
+
+Item {
+ id: testQtObject
+ property int importedScriptFunctionValue: MsbsiJs.testFunc(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/Msdsi.qml b/tests/benchmarks/declarative/holistic/data/jsImports/Msdsi.qml
new file mode 100644
index 0000000000..cd6ae72a56
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/Msdsi.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "msdsi.js" as MsdsiJs
+
+Item {
+ id: testQtObject
+ property int importedScriptFunctionValue: MsdsiJs.testFunc(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/Mssi.qml b/tests/benchmarks/declarative/holistic/data/jsImports/Mssi.qml
new file mode 100644
index 0000000000..604f2ebd6e
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/Mssi.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "mssi.js" as MssiJs
+
+Item {
+ id: testQtObject
+ property int importedScriptFunctionValue: MssiJs.testFunc(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/PragmaBm.qml b/tests/benchmarks/declarative/holistic/data/jsImports/PragmaBm.qml
new file mode 100644
index 0000000000..24709b93c2
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/PragmaBm.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "pragmaBmOne.js" as PragmaBmOneJs
+import "pragmaBmTwo.js" as PragmaBmTwoJs
+
+Item {
+ id: testQtObject
+
+ // value = 20 + 2 + 9 + (nbr times shared testFunc has been called previously == 0)
+ property int importedScriptFunctionValueOne: PragmaBmOneJs.testFuncOne(20)
+
+ // value = 20 + 3 + 9 + (nbr times shared testFunc has been called previously == 1)
+ property int importedScriptFunctionValueTwo: PragmaBmTwoJs.testFuncTwo(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/PragmaModuleBm.qml b/tests/benchmarks/declarative/holistic/data/jsImports/PragmaModuleBm.qml
new file mode 100644
index 0000000000..cac23cf412
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/PragmaModuleBm.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "pragmaModuleBm.js" as PragmaModuleBmJs
+
+Item {
+ id: testQtObject
+
+ // value = 20 + (Qt.test.Enum3 == 2) + 9 + (nbr times shared testFunc has been called previously = 0) + 9 + (nbr times shared testFunc has been called previously = 1)
+ property int importedScriptFunctionValue: PragmaModuleBmJs.testFuncThree(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/Slsi.qml b/tests/benchmarks/declarative/holistic/data/jsImports/Slsi.qml
new file mode 100644
index 0000000000..50d6de784e
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/Slsi.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "slsi.js" as SlsiJs
+
+Item {
+ id: testQtObject
+ property int importedScriptFunctionValue: SlsiJs.testFunc(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/Sssi.qml b/tests/benchmarks/declarative/holistic/data/jsImports/Sssi.qml
new file mode 100644
index 0000000000..b92a5a7cc9
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/Sssi.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+import "sssi.js" as SssiJs
+
+Item {
+ id: testQtObject
+ property int importedScriptFunctionValue: SssiJs.testFunc(20)
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi.js
new file mode 100644
index 0000000000..c4ea363cb7
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi.js
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports many other (non-nested) single, small, scripts.
+
+.import "mlbsi1.js" as Mlbsi1
+.import "mlbsi2.js" as Mlbsi2
+.import "mlbsi3.js" as Mlbsi3
+.import "mlbsi4.js" as Mlbsi4
+.import "mlbsi5.js" as Mlbsi5
+.import "mlbsi6.js" as Mlbsi6
+.import "mlbsi7.js" as Mlbsi7
+.import "mlbsi8.js" as Mlbsi8
+.import "mlbsi9.js" as Mlbsi9
+.import "mlbsi10.js" as Mlbsi10
+.import "mlbsi11.js" as Mlbsi11
+.import "mlbsi12.js" as Mlbsi12
+.import "mlbsi13.js" as Mlbsi13
+.import "mlbsi14.js" as Mlbsi14
+.import "mlbsi15.js" as Mlbsi15
+
+function testFunc(seedValue) {
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ var retn = cumulativeTotal * 0.53;
+ retn += Mlbsi1.testFunc(seedValue);
+ retn += Mlbsi2.testFunc(seedValue);
+ retn += Mlbsi3.testFunc(seedValue);
+ retn += Mlbsi4.testFunc(seedValue);
+ retn += Mlbsi5.testFunc(seedValue);
+ retn += Mlbsi6.testFunc(retn);
+ retn += Mlbsi7.testFunc(seedValue);
+ retn += Mlbsi8.testFunc(seedValue);
+ retn += Mlbsi9.testFunc(retn);
+ retn += Mlbsi10.testFunc(seedValue);
+ retn += Mlbsi11.testFunc(seedValue);
+ retn += Mlbsi12.testFunc(seedValue);
+ retn += Mlbsi13.testFunc(seedValue);
+ retn += Mlbsi14.testFunc(seedValue);
+ retn += Mlbsi15.testFunc(seedValue);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000017 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000017 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi1.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi1.js
new file mode 100644
index 0000000000..ad91dbf11e
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi1.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.145);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00001 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00001 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi10.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi10.js
new file mode 100644
index 0000000000..ce67b15163
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi10.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1045);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000010 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000010 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi11.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi11.js
new file mode 100644
index 0000000000..54836c520c
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi11.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1145);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000011 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000011 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi12.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi12.js
new file mode 100644
index 0000000000..c48a81854c
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi12.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1245);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000012 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000012 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi13.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi13.js
new file mode 100644
index 0000000000..f228e129fd
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi13.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1345);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000013 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000013 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi14.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi14.js
new file mode 100644
index 0000000000..e97c58ad90
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi14.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1445);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000014 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000014 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi15.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi15.js
new file mode 100644
index 0000000000..7c08c62f82
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi15.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1545);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000015 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000015 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi2.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi2.js
new file mode 100644
index 0000000000..19154f0580
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi2.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.245);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00002 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00002 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi3.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi3.js
new file mode 100644
index 0000000000..473a8b1145
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi3.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.345);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00003 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00003 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi4.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi4.js
new file mode 100644
index 0000000000..96f8851226
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi4.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.445);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00004 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00004 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi5.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi5.js
new file mode 100644
index 0000000000..0aa4a3b4de
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi5.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.545);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00005 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00005 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi6.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi6.js
new file mode 100644
index 0000000000..550e4054f7
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi6.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.645);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00006 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00006 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi7.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi7.js
new file mode 100644
index 0000000000..a3502c2bdb
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi7.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.745);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00007 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00007 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi8.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi8.js
new file mode 100644
index 0000000000..af9c574e7c
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi8.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.845);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00008 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00008 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi9.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi9.js
new file mode 100644
index 0000000000..1f233a6eed
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlbsi9.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.945);
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00009 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00009 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi.js
new file mode 100644
index 0000000000..59df07c1c9
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi.js
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+
+.import "mldsi1.js" as Mldsi1
+
+function testFunc(seedValue) {
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ var retn = cumulativeTotal * 0.5;
+ retn *= Mldsi1.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000017 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000017 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi1.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi1.js
new file mode 100644
index 0000000000..94d186b88c
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi1.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi2.js" as Msdsi2
+
+function testFunc(seedValue) {
+ var retn = 0.15;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi2.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00001 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00001 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi10.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi10.js
new file mode 100644
index 0000000000..5a60306209
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi10.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi11.js" as Msdsi11
+
+function testFunc(seedValue) {
+ var retn = 0.105;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi11.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000010 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000010 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi11.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi11.js
new file mode 100644
index 0000000000..8a7b95304c
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi11.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi12.js" as Msdsi12
+
+function testFunc(seedValue) {
+ var retn = 0.115;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi12.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000011 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000011 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi12.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi12.js
new file mode 100644
index 0000000000..30f371649f
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi12.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi13.js" as Msdsi13
+
+function testFunc(seedValue) {
+ var retn = 0.125;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi13.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000012 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000012 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi13.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi13.js
new file mode 100644
index 0000000000..65f3e4a952
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi13.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi14.js" as Msdsi14
+
+function testFunc(seedValue) {
+ var retn = 0.135;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi14.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000013 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000013 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi14.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi14.js
new file mode 100644
index 0000000000..5dd6dcfe49
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi14.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi15.js" as Msdsi15
+
+function testFunc(seedValue) {
+ var retn = 0.145;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi15.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000014 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000014 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi15.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi15.js
new file mode 100644
index 0000000000..c6873d8e72
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi15.js
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It is imported by another script.
+
+function testFunc(seedValue) {
+ var retn = 0.155;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= (seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.000015 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.000015 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi2.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi2.js
new file mode 100644
index 0000000000..a876ebee7d
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi2.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi3.js" as Msdsi3
+
+function testFunc(seedValue) {
+ var retn = 0.25;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi3.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00002 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00002 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi3.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi3.js
new file mode 100644
index 0000000000..cab8b2662d
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi3.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi4.js" as Msdsi4
+
+function testFunc(seedValue) {
+ var retn = 0.35;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi4.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00003 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00003 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi4.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi4.js
new file mode 100644
index 0000000000..69c14a0278
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi4.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi5.js" as Msdsi5
+
+function testFunc(seedValue) {
+ var retn = 0.45;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi5.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00004 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00004 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi5.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi5.js
new file mode 100644
index 0000000000..889766f3ce
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi5.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi6.js" as Msdsi6
+
+function testFunc(seedValue) {
+ var retn = 0.55;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi6.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00005 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00005 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi6.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi6.js
new file mode 100644
index 0000000000..332b60679e
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi6.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi7.js" as Msdsi7
+
+function testFunc(seedValue) {
+ var retn = 0.65;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi7.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00006 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00006 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi7.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi7.js
new file mode 100644
index 0000000000..0b1ef645b0
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi7.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi8.js" as Msdsi8
+
+function testFunc(seedValue) {
+ var retn = 0.75;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi8.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00007 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00007 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi8.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi8.js
new file mode 100644
index 0000000000..2f4145aba9
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi8.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi9.js" as Msdsi9
+
+function testFunc(seedValue) {
+ var retn = 0.85;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi9.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00008 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00008 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mldsi9.js b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi9.js
new file mode 100644
index 0000000000..d06a00d31c
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mldsi9.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports other large scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi10.js" as Msdsi10
+
+function testFunc(seedValue) {
+ var retn = 0.95;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn *= (1 + (cumulativeTotal * 0.001));
+ retn *= Msdsi10.testFunc(seedValue + retn);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00009 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00009 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mlsi.js b/tests/benchmarks/declarative/holistic/data/jsImports/mlsi.js
new file mode 100644
index 0000000000..fbc9b41882
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mlsi.js
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports many other (non-nested) single, large, scripts,
+// and also imports many other nested, large scripts.
+
+.import "mldsi4.js" as Mldsi4
+.import "mldsi9.js" as Mldsi9
+.import "mlbsi1.js" as Mlbsi1
+.import "mlbsi2.js" as Mlbsi2
+.import "mlbsi3.js" as Mlbsi3
+.import "mlbsi4.js" as Mlbsi4
+.import "mlbsi5.js" as Mlbsi5
+.import "mlbsi6.js" as Mlbsi6
+.import "mlbsi7.js" as Mlbsi7
+.import "mlbsi8.js" as Mlbsi8
+.import "mlbsi9.js" as Mlbsi9
+.import "mlbsi10.js" as Mlbsi10
+.import "mlbsi11.js" as Mlbsi11
+.import "mlbsi12.js" as Mlbsi12
+.import "mlbsi13.js" as Mlbsi13
+.import "mlbsi14.js" as Mlbsi14
+.import "mlbsi15.js" as Mlbsi15
+
+function testFunc(seedValue) {
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ var retn = cumulativeTotal;
+ retn += Mlbsi1.testFunc(seedValue);
+ retn += Mlbsi2.testFunc(seedValue);
+ retn += Mlbsi3.testFunc(retn);
+ retn += Mlbsi4.testFunc(seedValue);
+ retn += Mlbsi5.testFunc(seedValue);
+ retn += Mlbsi6.testFunc(seedValue);
+ retn *= Mldsi9.testFunc(retn);
+ retn += Mlbsi7.testFunc(seedValue);
+ retn += Mlbsi8.testFunc(retn);
+ retn += Mlbsi9.testFunc(seedValue);
+ retn += Mlbsi10.testFunc(seedValue);
+ retn += Mlbsi11.testFunc(seedValue);
+ retn *= Mldsi4.testFunc(retn);
+ retn += Mlbsi12.testFunc(seedValue);
+ retn += Mlbsi13.testFunc(retn);
+ retn += Mlbsi14.testFunc(seedValue);
+ retn += Mlbsi15.testFunc(seedValue);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00001 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00001 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/moduleBm.js b/tests/benchmarks/declarative/holistic/data/jsImports/moduleBm.js
new file mode 100644
index 0000000000..7de7e89b9a
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/moduleBm.js
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+.import Qt.test 1.0 as QtTest
+
+function testFunc(seedValue) {
+ var retn = QtTest.EnumValue3;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn += (cumulativeTotal * 0.45);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00001 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00001 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
+
+
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi.js
new file mode 100644
index 0000000000..c60ce88dd9
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi.js
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports many other (non-nested) single, small, scripts.
+
+.import "msbsi1.js" as Msbsi1
+.import "msbsi2.js" as Msbsi2
+.import "msbsi3.js" as Msbsi3
+.import "msbsi4.js" as Msbsi4
+.import "msbsi5.js" as Msbsi5
+.import "msbsi6.js" as Msbsi6
+.import "msbsi7.js" as Msbsi7
+.import "msbsi8.js" as Msbsi8
+.import "msbsi9.js" as Msbsi9
+.import "msbsi10.js" as Msbsi10
+.import "msbsi11.js" as Msbsi11
+.import "msbsi12.js" as Msbsi12
+.import "msbsi13.js" as Msbsi13
+.import "msbsi14.js" as Msbsi14
+.import "msbsi15.js" as Msbsi15
+
+function testFunc(seedValue) {
+ var retn = 10 * (seedValue * 0.45);
+ retn += Msbsi1.testFunc(seedValue);
+ retn += Msbsi2.testFunc(seedValue);
+ retn += Msbsi3.testFunc(seedValue);
+ retn += Msbsi4.testFunc(seedValue);
+ retn += Msbsi5.testFunc(seedValue);
+ retn += Msbsi6.testFunc(seedValue);
+ retn += Msbsi7.testFunc(seedValue);
+ retn += Msbsi8.testFunc(seedValue);
+ retn += Msbsi9.testFunc(seedValue);
+ retn += Msbsi10.testFunc(seedValue);
+ retn += Msbsi11.testFunc(seedValue);
+ retn += Msbsi12.testFunc(seedValue);
+ retn += Msbsi13.testFunc(seedValue);
+ retn += Msbsi14.testFunc(seedValue);
+ retn += Msbsi15.testFunc(seedValue);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi1.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi1.js
new file mode 100644
index 0000000000..422558121d
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi1.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.145);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi10.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi10.js
new file mode 100644
index 0000000000..0ee3a369d6
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi10.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1045);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi11.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi11.js
new file mode 100644
index 0000000000..40e993c9bd
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi11.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1145);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi12.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi12.js
new file mode 100644
index 0000000000..ba8d9d6bda
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi12.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1245);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi13.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi13.js
new file mode 100644
index 0000000000..9544c9fe74
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi13.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1345);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi14.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi14.js
new file mode 100644
index 0000000000..df70f05452
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi14.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1445);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi15.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi15.js
new file mode 100644
index 0000000000..82c1ac581d
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi15.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.1545);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi2.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi2.js
new file mode 100644
index 0000000000..cf10dcb52e
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi2.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.245);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi3.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi3.js
new file mode 100644
index 0000000000..d743c44f6a
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi3.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.345);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi4.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi4.js
new file mode 100644
index 0000000000..df8f977ba5
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi4.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.445);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi5.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi5.js
new file mode 100644
index 0000000000..3c00c1cdf0
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi5.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.545);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi6.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi6.js
new file mode 100644
index 0000000000..0aa0e93dbd
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi6.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.645);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi7.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi7.js
new file mode 100644
index 0000000000..933fca8a72
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi7.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.745);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi8.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi8.js
new file mode 100644
index 0000000000..4f76257e72
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi8.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.845);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msbsi9.js b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi9.js
new file mode 100644
index 0000000000..3b2433e076
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msbsi9.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+// It is imported from another script.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.945);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi.js
new file mode 100644
index 0000000000..13182480c6
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi.js
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+
+.import "msdsi1.js" as Msdsi1
+
+function testFunc(seedValue) {
+ var retn = 0.5;
+ retn *= Msdsi1.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi1.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi1.js
new file mode 100644
index 0000000000..1d987567cc
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi1.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi2.js" as Msdsi2
+
+function testFunc(seedValue) {
+ var retn = 0.15;
+ retn *= Msdsi2.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi10.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi10.js
new file mode 100644
index 0000000000..90b3e8173b
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi10.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi11.js" as Msdsi11
+
+function testFunc(seedValue) {
+ var retn = 0.105;
+ retn *= Msdsi11.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi11.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi11.js
new file mode 100644
index 0000000000..1df1dae7e0
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi11.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi12.js" as Msdsi12
+
+function testFunc(seedValue) {
+ var retn = 0.115;
+ retn *= Msdsi12.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi12.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi12.js
new file mode 100644
index 0000000000..4c5d6bcdb4
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi12.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi13.js" as Msdsi13
+
+function testFunc(seedValue) {
+ var retn = 0.125;
+ retn *= Msdsi13.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi13.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi13.js
new file mode 100644
index 0000000000..858233dec7
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi13.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi14.js" as Msdsi14
+
+function testFunc(seedValue) {
+ var retn = 0.135;
+ retn *= Msdsi14.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi14.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi14.js
new file mode 100644
index 0000000000..bafceb0931
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi14.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi15.js" as Msdsi15
+
+function testFunc(seedValue) {
+ var retn = 0.145;
+ retn *= Msdsi15.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi15.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi15.js
new file mode 100644
index 0000000000..c3d2c0ba01
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi15.js
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It is imported by another script.
+
+function testFunc(seedValue) {
+ var retn = 0.155;
+ retn *= (seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi2.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi2.js
new file mode 100644
index 0000000000..2d63a9d0a8
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi2.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi3.js" as Msdsi3
+
+function testFunc(seedValue) {
+ var retn = 0.25;
+ retn *= Msdsi3.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi3.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi3.js
new file mode 100644
index 0000000000..c281240f15
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi3.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi4.js" as Msdsi4
+
+function testFunc(seedValue) {
+ var retn = 0.35;
+ retn *= Msdsi4.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi4.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi4.js
new file mode 100644
index 0000000000..eb44d0f5e2
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi4.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi5.js" as Msdsi5
+
+function testFunc(seedValue) {
+ var retn = 0.45;
+ retn *= Msdsi5.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi5.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi5.js
new file mode 100644
index 0000000000..fd3abc3a7a
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi5.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi6.js" as Msdsi6
+
+function testFunc(seedValue) {
+ var retn = 0.55;
+ retn *= Msdsi6.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi6.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi6.js
new file mode 100644
index 0000000000..eb5adde3ca
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi6.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi7.js" as Msdsi7
+
+function testFunc(seedValue) {
+ var retn = 0.65;
+ retn *= Msdsi7.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi7.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi7.js
new file mode 100644
index 0000000000..32e41dc642
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi7.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi8.js" as Msdsi8
+
+function testFunc(seedValue) {
+ var retn = 0.75;
+ retn *= Msdsi8.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi8.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi8.js
new file mode 100644
index 0000000000..ecdb97f5b2
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi8.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi9.js" as Msdsi9
+
+function testFunc(seedValue) {
+ var retn = 0.85;
+ retn *= Msdsi9.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/msdsi9.js b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi9.js
new file mode 100644
index 0000000000..9082cddd3e
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/msdsi9.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports other small scripts which are deeply nested.
+// It is imported by another script.
+
+.import "msdsi10.js" as Msdsi10
+
+function testFunc(seedValue) {
+ var retn = 0.95;
+ retn *= Msdsi10.testFunc(seedValue + retn);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/mssi.js b/tests/benchmarks/declarative/holistic/data/jsImports/mssi.js
new file mode 100644
index 0000000000..2254c5c585
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/mssi.js
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It imports many other (non-nested) single, small, scripts,
+// and also imports many other nested, small scripts.
+
+.import "msdsi4.js" as Msdsi4
+.import "msdsi9.js" as Msdsi9
+.import "msbsi1.js" as Msbsi1
+.import "msbsi2.js" as Msbsi2
+.import "msbsi3.js" as Msbsi3
+.import "msbsi4.js" as Msbsi4
+.import "msbsi5.js" as Msbsi5
+.import "msbsi6.js" as Msbsi6
+.import "msbsi7.js" as Msbsi7
+.import "msbsi8.js" as Msbsi8
+.import "msbsi9.js" as Msbsi9
+.import "msbsi10.js" as Msbsi10
+.import "msbsi11.js" as Msbsi11
+.import "msbsi12.js" as Msbsi12
+.import "msbsi13.js" as Msbsi13
+.import "msbsi14.js" as Msbsi14
+.import "msbsi15.js" as Msbsi15
+
+function testFunc(seedValue) {
+ var retn = 10 * (seedValue * 0.85);
+ retn += Msbsi1.testFunc(seedValue);
+ retn += Msbsi2.testFunc(seedValue);
+ retn += Msbsi3.testFunc(retn);
+ retn += Msbsi4.testFunc(seedValue);
+ retn += Msbsi5.testFunc(seedValue);
+ retn += Msbsi6.testFunc(seedValue);
+ retn *= Msdsi9.testFunc(retn);
+ retn += Msbsi7.testFunc(seedValue);
+ retn += Msbsi8.testFunc(retn);
+ retn += Msbsi9.testFunc(seedValue);
+ retn += Msbsi10.testFunc(seedValue);
+ retn += Msbsi11.testFunc(seedValue);
+ retn *= Msdsi4.testFunc(retn);
+ retn += Msbsi12.testFunc(seedValue);
+ retn += Msbsi13.testFunc(retn);
+ retn += Msbsi14.testFunc(seedValue);
+ retn += Msbsi15.testFunc(seedValue);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/pragmaBmOne.js b/tests/benchmarks/declarative/holistic/data/jsImports/pragmaBmOne.js
new file mode 100644
index 0000000000..e3c54000bb
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/pragmaBmOne.js
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports a shared library script.
+.import "pragmaLib.js" as PragmaLibJs
+
+function testFuncOne(seedValue) {
+ var retn = seedValue + 2;
+ retn += PragmaLibJs.testFunc();
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/pragmaBmTwo.js b/tests/benchmarks/declarative/holistic/data/jsImports/pragmaBmTwo.js
new file mode 100644
index 0000000000..9a28fafbca
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/pragmaBmTwo.js
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports a shared library script.
+.import "pragmaLib.js" as PragmaLibJs
+
+function testFuncTwo(seedValue) {
+ var retn = seedValue + 3;
+ retn += PragmaLibJs.testFunc();
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/pragmaLib.js b/tests/benchmarks/declarative/holistic/data/jsImports/pragmaLib.js
new file mode 100644
index 0000000000..a247d75ed1
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/pragmaLib.js
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+// It is a shared script, with data which should be shared.
+.pragma library
+
+var sharedValue = 9;
+
+function testFunc() {
+ var retn = sharedValue;
+ sharedValue += 1; // increment the shared value
+ return retn;
+}
+
+function testFuncBig(seedValue) {
+ var retn = sharedValue;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn += (cumulativeTotal * 0.45);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ sharedValue += 1; // increment the shared value
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00001 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00001 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
+
+
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/pragmaModuleBm.js b/tests/benchmarks/declarative/holistic/data/jsImports/pragmaModuleBm.js
new file mode 100644
index 0000000000..6f363082da
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/pragmaModuleBm.js
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It imports a QML module and two other scripts.
+// Each of those two other scripts imports a single script,
+// which is a .pragma library script (shared between the two).
+
+.import Qt.test 1.0 as QtTest
+.import "pragmaBmOne.js" as PragmaBmOneJs
+.import "pragmaBmTwo.js" as PragmaBmTwoJs
+
+function testFuncThree(seedValue) {
+ var retn = seedValue + QtTest.EnumValue3;
+ retn += PragmaBmOneJs.testFuncOne(seedValue);
+ retn += PragmaBmTwoJs.testFuncTwo(seedValue);
+ return retn;
+}
+
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/slsi.js b/tests/benchmarks/declarative/holistic/data/jsImports/slsi.js
new file mode 100644
index 0000000000..c1741087fa
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/slsi.js
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, large, imported script.
+// It doesn't import any other scripts.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ var firstFactor = calculateFirstFactor(seedValue);
+ var secondFactor = calculateSecondFactor(seedValue);
+ var modificationTerm = calculateModificationTerm(seedValue);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (seedValue * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (seedValue * 50)) {
+ break;
+ }
+ }
+ }
+ retn += (cumulativeTotal * 0.45);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
+
+function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00001 / seedValue));
+ return firstFactor;
+}
+
+function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00001 / seedValue));
+ return secondFactor;
+}
+
+function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((calculateFirstFactor(seedValue) * seedValue) / 3) + (4*calculateSecondFactor(seedValue) * seedValue * 1.33)) + (calculateSecondFactor(seedValue) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+}
+
+
diff --git a/tests/benchmarks/declarative/holistic/data/jsImports/sssi.js b/tests/benchmarks/declarative/holistic/data/jsImports/sssi.js
new file mode 100644
index 0000000000..b52e88dc53
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsImports/sssi.js
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This JavaScript file is a single, small, imported script.
+// It doesn't import any other scripts.
+
+function testFunc(seedValue) {
+ var retn = 5;
+ retn += (seedValue * 0.45);
+ retn *= (1 + (3.1415962 / seedValue));
+ retn /= 2.41497;
+ retn -= (seedValue * -1);
+ return retn;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsTargets/JsOne.qml b/tests/benchmarks/declarative/holistic/data/jsTargets/JsOne.qml
new file mode 100644
index 0000000000..fcdd0819d1
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsTargets/JsOne.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Item {
+ id: root
+ property int dynamicWidth: 10
+ property int widthSignaledProperty: 20
+
+ Rectangle {
+ width: 100
+ height: 50
+ color: "red"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+
+ onDynamicWidthChanged: {
+ widthSignaledProperty = dynamicWidth + (20/4) + 7 - 1;
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/jsTargets/JsTwo.qml b/tests/benchmarks/declarative/holistic/data/jsTargets/JsTwo.qml
new file mode 100644
index 0000000000..980c76f21e
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/jsTargets/JsTwo.qml
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Item {
+ id: root
+ property int dynamicWidth: 10
+ property int widthSignaledProperty: 20
+
+ Rectangle {
+ width: 100
+ height: 50
+ color: "red"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+
+ function calculateFirstFactor(seedValue) {
+ var firstFactor = (0.45 * (9.3 / 3.1) - 0.90);
+ firstFactor *= (1 + (0.00001 / seedValue));
+ return firstFactor;
+ }
+
+ function calculateSecondFactor(seedValue) {
+ var secondFactor = 0.78 * (6.3 / 2.1) - (0.39 * 4);
+ secondFactor *= (1 + (0.00001 / seedValue));
+ return secondFactor;
+ }
+
+ function calculateModificationTerm(seedValue) {
+ var modificationTerm = (12 + (9*7) - 54 + 16 - ((root.calculateFirstFactor(seedValue + 0.3) * seedValue) / 3) + (4*root.calculateSecondFactor(seedValue+2) * seedValue * 1.33)) + (root.calculateSecondFactor(seedValue+1) * seedValue);
+ modificationTerm = modificationTerm + (33/2) + 19 - (9*2) - (61*3) + 177;
+ return modificationTerm;
+ }
+
+ onDynamicWidthChanged: {
+ // do a bit of maths
+ var firstFactor = root.calculateFirstFactor(8);
+ var secondFactor = root.calculateSecondFactor(dynamicWidth / firstFactor);
+ var modificationTerm = root.calculateModificationTerm(dynamicWidth / secondFactor);
+
+ // do some regexp matching
+ var someString = "This is a random string which we'll perform regular expression matching on to reduce considerably. This is meant to be part of a complex javascript expression whose evaluation takes considerably longer than the creation cost of QScriptValue.";
+ var regexpPattern = new RegExp("is", "i");
+ var regexpOutputLength = 0;
+ var temp = regexpPattern.exec(someString);
+ while (temp == "is") {
+ regexpOutputLength += 4;
+ regexpOutputLength *= 2;
+ temp = regexpPattern.exec(someString);
+ if (regexpOutputLength > (dynamicWidth * 3)) {
+ temp = "break";
+ }
+ }
+
+ // spin in a for loop for a while
+ var i = 0;
+ var j = 0;
+ var cumulativeTotal = 3;
+ for (i = 20; i > 1; i--) {
+ for (j = 31; j > 5; j--) {
+ var branchVariable = i + j;
+ if (branchVariable % 3 == 0) {
+ cumulativeTotal -= secondFactor;
+ } else {
+ cumulativeTotal += firstFactor;
+ }
+
+ if (cumulativeTotal > (dynamicWidth * 50)) {
+ break;
+ }
+ }
+ }
+
+ // and update the property
+ widthSignaledProperty = (dynamicWidth + (20/4) + 7 - 1) * modificationTerm + regexpOutputLength - (cumulativeTotal / 73);
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/largeTargets/gridview-example.qml b/tests/benchmarks/declarative/holistic/data/largeTargets/gridview-example.qml
new file mode 100644
index 0000000000..e904c0a647
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/largeTargets/gridview-example.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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 1.0
+
+Rectangle {
+ width: 300; height: 400
+ color: "white"
+
+ ListModel {
+ id: appModel
+ ListElement { name: "Music"; shade: "blue" }
+ ListElement { name: "Movies"; shade: "red" }
+ ListElement { name: "Camera"; shade: "green" }
+ ListElement { name: "Calendar"; shade: "yellow" }
+ ListElement { name: "Messaging"; shade: "cyan" }
+ ListElement { name: "Todo List"; shade: "magenta" }
+ ListElement { name: "Contacts"; shade: "black" }
+ }
+
+ Component {
+ id: appDelegate
+
+ Item {
+ width: 100; height: 100
+
+ Rectangle {
+ id: myColoredIcon
+ width: 20
+ height: 20
+ y: 20; anchors.horizontalCenter: parent.horizontalCenter
+ color: shade
+ }
+ Text {
+ anchors { top: myColoredIcon.bottom; horizontalCenter: parent.horizontalCenter }
+ text: name
+ }
+ }
+ }
+
+ Component {
+ id: appHighlight
+ Rectangle { width: 80; height: 80; color: "lightsteelblue" }
+ }
+
+ GridView {
+ anchors.fill: parent
+ cellWidth: 100; cellHeight: 100
+ highlight: appHighlight
+ focus: true
+ model: appModel
+ delegate: appDelegate
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/largeTargets/layoutdirection.qml b/tests/benchmarks/declarative/holistic/data/largeTargets/layoutdirection.qml
new file mode 100644
index 0000000000..9b6a652c14
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/largeTargets/layoutdirection.qml
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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 1.1
+
+Rectangle {
+
+ width: column.width + 100
+ height: column.height + 100
+ property int direction: Qt.application.layoutDirection
+
+ Column {
+ id: column
+ spacing: 10
+ anchors.centerIn: parent
+ width: 230
+
+ Text {
+ text: "Row"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Row {
+ layoutDirection: direction
+ spacing: 10
+ move: Transition {
+ NumberAnimation {
+ properties: "x"
+ }
+ }
+ Repeater {
+ model: 4
+ Loader {
+ property int value: index
+ sourceComponent: delegate
+ }
+ }
+ }
+ Text {
+ text: "Grid"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Grid {
+ layoutDirection: direction
+ spacing: 10; columns: 4
+ move: Transition {
+ NumberAnimation {
+ properties: "x"
+ }
+ }
+ Repeater {
+ model: 11
+ Loader {
+ property int value: index
+ sourceComponent: delegate
+ }
+ }
+ }
+ Text {
+ text: "Flow"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Flow {
+ layoutDirection: direction
+ spacing: 10; width: parent.width
+ move: Transition {
+ NumberAnimation {
+ properties: "x"
+ }
+ }
+ Repeater {
+ model: 10
+ Loader {
+ property int value: index
+ sourceComponent: delegate
+ }
+ }
+ }
+ Rectangle {
+ height: 50; width: parent.width
+ color: mouseArea.pressed ? "black" : "gray"
+ Text {
+ text: direction ? "Right to left" : "Left to right"
+ color: "white"
+ font.pixelSize: 16
+ anchors.centerIn: parent
+ }
+ MouseArea {
+ id: mouseArea
+ onClicked: {
+ if (direction == Qt.LeftToRight) {
+ direction = Qt.RightToLeft;
+ } else {
+ direction = Qt.LeftToRight;
+ }
+ }
+ anchors.fill: parent
+ }
+ }
+ }
+
+ Component {
+ id: delegate
+ Rectangle {
+ width: 50; height: 50
+ color: Qt.rgba(0.8/(parent.value+1),0.8/(parent.value+1),0.8/(parent.value+1),1.0)
+ Text {
+ text: parent.parent.value+1
+ color: "white"
+ font.pixelSize: 20
+ anchors.centerIn: parent
+ }
+ }
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/largeTargets/mousearea-example.qml b/tests/benchmarks/declarative/holistic/data/largeTargets/mousearea-example.qml
new file mode 100644
index 0000000000..9bca78ff60
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/largeTargets/mousearea-example.qml
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Nokia Corporation and its Subsidiary(-ies) 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 1.0
+
+Rectangle {
+ id: box
+ width: 350; height: 250
+
+ Rectangle {
+ id: redSquare
+ width: 80; height: 80
+ anchors.top: parent.top; anchors.left: parent.left; anchors.margins: 10
+ color: "red"
+
+ Text { text: "Click"; font.pixelSize: 16; anchors.centerIn: parent }
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+
+ onEntered: info.text = 'Entered'
+ onExited: info.text = 'Exited (pressed=' + pressed + ')'
+
+ onPressed: {
+ info.text = 'Pressed (button=' + (mouse.button == Qt.RightButton ? 'right' : 'left')
+ + ' shift=' + (mouse.modifiers & Qt.ShiftModifier ? 'true' : 'false') + ')'
+ var posInBox = redSquare.mapToItem(box, mouse.x, mouse.y)
+ posInfo.text = + mouse.x + ',' + mouse.y + ' in square'
+ + ' (' + posInBox.x + ',' + posInBox.y + ' in window)'
+ }
+
+ onReleased: {
+ info.text = 'Released (isClick=' + mouse.isClick + ' wasHeld=' + mouse.wasHeld + ')'
+ posInfo.text = ''
+ }
+
+ onPressAndHold: info.text = 'Press and hold'
+ onClicked: info.text = 'Clicked (wasHeld=' + mouse.wasHeld + ')'
+ onDoubleClicked: info.text = 'Double clicked'
+ }
+ }
+
+ Rectangle {
+ id: blueSquare
+ width: 80; height: 80
+ x: box.width - width - 10; y: 10 // making this item draggable, so don't use anchors
+ color: "blue"
+
+ Text { text: "Drag"; font.pixelSize: 16; color: "white"; anchors.centerIn: parent }
+
+ MouseArea {
+ anchors.fill: parent
+ drag.target: blueSquare
+ drag.axis: Drag.XandYAxis
+ drag.minimumX: 0
+ drag.maximumX: box.width - parent.width
+ drag.minimumY: 0
+ drag.maximumY: box.height - parent.width
+ }
+ }
+
+ Text {
+ id: info
+ anchors.bottom: posInfo.top; anchors.horizontalCenter: parent.horizontalCenter; anchors.margins: 30
+
+ onTextChanged: console.log(text)
+ }
+
+ Text {
+ id: posInfo
+ anchors.bottom: parent.bottom; anchors.horizontalCenter: parent.horizontalCenter; anchors.margins: 30
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/resolutionTargets/ResolveOne.qml b/tests/benchmarks/declarative/holistic/data/resolutionTargets/ResolveOne.qml
new file mode 100644
index 0000000000..7a5ea39fff
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/resolutionTargets/ResolveOne.qml
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file has some nested items and does a lot of id resolution.
+// This will allow us to benchmark the cost of resolving names in
+// bindings.
+
+import QtQuick 1.0
+
+Item {
+ id: root
+ property int baseWidth: 500
+ property int baseHeight: 600
+ property string baseColor: "red"
+
+ Item {
+ id: childOne
+ property int baseWidth: root.baseWidth - 1
+ property int baseHeight: root.baseHeight - 1
+ property string baseColor: root.baseColor
+
+ Item {
+ id: childTwo
+ property int baseWidth: root.baseWidth - 2
+ property int baseHeight: childOne.baseHeight - 1
+ property string baseColor: childOne.baseColor
+
+ Item {
+ id: childThree
+ property int baseWidth: childOne.baseWidth - 2
+ property int baseHeight: root.baseHeight - 3
+ property string baseColor: "blue"
+
+ Item {
+ id: childFour
+ property int baseWidth: childTwo.baseWidth - 2
+ property int baseHeight: childThree.baseHeight - 1
+ property string baseColor: "earthy " + root.baseColor
+
+ Item {
+ id: childFive
+ property int baseWidth: root.baseWidth - 5
+ property int baseHeight: childFour.baseHeight - 1
+ property string baseColor: "carnelian " + childTwo.baseColor
+ }
+ }
+
+ Item {
+ id: childSix
+ property int baseWidth: parent.baseWidth - 3
+ property int baseHeight: root.baseHeight - 6
+ property string baseColor: "rust " + root.baseColor
+
+ Item {
+ id: childSeven
+ property int baseWidth: childOne.baseWidth - 6
+ property int baseHeight: childTwo.baseHeight - 5
+ property string baseColor: "sky " + childThree.baseColor
+ }
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ width: childOne.baseWidth
+ height: childOne.baseHeight
+ color: parent.baseColor
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/CppToJs.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/CppToJs.qml
new file mode 100644
index 0000000000..11c6b37f05
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/CppToJs.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import "cppToJs.js" as CppToJs
+
+Item {
+ id: jsConsumer
+ property int sideEffect: 10
+
+ function callJsFunction() {
+ jsConsumer.sideEffect = jsConsumer.sideEffect + CppToJs.nextValue;
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/CppToQml.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/CppToQml.qml
new file mode 100644
index 0000000000..23adcd957b
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/CppToQml.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Item {
+ id: root
+ property int arbitrary: 10
+ property int dependent: arbitrary + 5
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppEight.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppEight.qml
new file mode 100644
index 0000000000..1379f62771
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppEight.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a nonconst CPP function with an integer return value and an integer argument.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + arbitraryVariantProvider.modifyVariantChangeCount(arbitraryVariantConsumer.sideEffect);
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppEleven.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppEleven.qml
new file mode 100644
index 0000000000..53479e9cb6
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppEleven.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property variant someVariant;
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a nonconst CPP function with variant return value and variant + integer arguments.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + 3;
+ var tempVariant = arbitraryVariantProvider.setVariantToFilledPixmap(sideEffect + 183, sideEffect + 134, sideEffect + 38, sideEffect + 77, sideEffect + 21);
+ someVariant = arbitraryVariantProvider.setVariantAddCount(sideEffect, tempVariant);
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppFive.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppFive.qml
new file mode 100644
index 0000000000..52320eb91e
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppFive.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a const CPP function with an integer return value and no arguments.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + arbitraryVariantProvider.variantChangeCount();
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppFour.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppFour.qml
new file mode 100644
index 0000000000..ab567012e3
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppFour.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a nonconst CPP function with no return value and an integer argument.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + 2;
+ arbitraryVariantProvider.setVariantChangeCount(arbitraryVariantConsumer.sideEffect);
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppNine.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppNine.qml
new file mode 100644
index 0000000000..d8f99f4623
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppNine.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property variant someVariant;
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a const CPP function with variant return value and integer arguments.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + 3;
+ someVariant = arbitraryVariantProvider.possibleVariant(sideEffect, sideEffect * 2, sideEffect * 5);
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppOne.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppOne.qml
new file mode 100644
index 0000000000..057b50c8ec
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppOne.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a const CPP function with no return value and no arguments.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + 2;
+ arbitraryVariantProvider.doNothing();
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppSeven.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppSeven.qml
new file mode 100644
index 0000000000..9f9735bf36
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppSeven.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a const CPP function with an integer return value and an integer argument.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + arbitraryVariantProvider.countPlus(arbitraryVariantConsumer.sideEffect);
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppSix.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppSix.qml
new file mode 100644
index 0000000000..f5cd9bf722
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppSix.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a nonconst CPP function with an integer return value and no arguments.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + arbitraryVariantProvider.modifyVariantChangeCount();
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppTen.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppTen.qml
new file mode 100644
index 0000000000..b9f90e0596
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppTen.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property variant someVariant;
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a nonconst CPP function with variant return value and integer arguments.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + 3;
+ someVariant = arbitraryVariantProvider.setVariantToFilledPixmap(sideEffect + 183, sideEffect + 134, sideEffect + 38, sideEffect + 77, sideEffect + 21);
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppThree.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppThree.qml
new file mode 100644
index 0000000000..65ed8b9925
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppThree.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a const CPP function with no return value and an integer argument.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + 2;
+ arbitraryVariantProvider.doNothing(arbitraryVariantConsumer.sideEffect);
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppTwo.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppTwo.qml
new file mode 100644
index 0000000000..221e196eb8
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/JsToCppTwo.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: arbitraryVariantConsumer
+ property MyArbitraryVariantProvider a: MyArbitraryVariantProvider { id: arbitraryVariantProvider }
+ property int sideEffect: 10
+
+ function callCppFunction() {
+ // in this case, we call a nonconst CPP function with no return value and no arguments.
+ arbitraryVariantConsumer.sideEffect = arbitraryVariantConsumer.sideEffect + 2;
+ arbitraryVariantProvider.incrementVariantChangeCount();
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/ScarceOne.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/ScarceOne.qml
new file mode 100644
index 0000000000..531849dcce
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/ScarceOne.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: scarceResourceConsumer
+
+ property MyScarceResourceProvider a: MyScarceResourceProvider { id: scarceResourceProvider }
+
+ property variant ssr;
+ property variant lsr;
+
+ function copyScarceResources() {
+ ssr = scarceResourceProvider.smallScarceResource;
+ lsr = scarceResourceProvider.largeScarceResource;
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/ScarceTwo.qml b/tests/benchmarks/declarative/holistic/data/scopeSwitching/ScarceTwo.qml
new file mode 100644
index 0000000000..a9ef7e355d
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/ScarceTwo.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import Qt.test 1.0
+
+Item {
+ id: scarceResourceConsumer
+
+ property MyScarceResourceProvider a: MyScarceResourceProvider { id: scarceResourceProvider }
+
+ property variant ssr: scarceResourceProvider.smallScarceResource
+ property variant lsr: scarceResourceProvider.largeScarceResource
+}
diff --git a/tests/benchmarks/declarative/holistic/data/scopeSwitching/cppToJs.js b/tests/benchmarks/declarative/holistic/data/scopeSwitching/cppToJs.js
new file mode 100644
index 0000000000..ace7ec5f5e
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/scopeSwitching/cppToJs.js
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+.pragma library
+
+var generatedValue = 5;
+
+function generateNextValue() {
+ generatedValue += 1;
+ return generatedValue;
+}
diff --git a/tests/benchmarks/declarative/holistic/data/smallTargets/SmallFour.qml b/tests/benchmarks/declarative/holistic/data/smallTargets/SmallFour.qml
new file mode 100644
index 0000000000..fac4966d41
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/smallTargets/SmallFour.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Text {
+ text: "Hello World!"
+ font.family: "Helvetica"
+ font.pointSize: 24
+ color: "red"
+}
diff --git a/tests/benchmarks/declarative/holistic/data/smallTargets/SmallOne.qml b/tests/benchmarks/declarative/holistic/data/smallTargets/SmallOne.qml
new file mode 100644
index 0000000000..e055fd94f7
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/smallTargets/SmallOne.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Rectangle {
+ width: 100
+ height: 100
+ color: "red"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+}
diff --git a/tests/benchmarks/declarative/holistic/data/smallTargets/SmallThree.qml b/tests/benchmarks/declarative/holistic/data/smallTargets/SmallThree.qml
new file mode 100644
index 0000000000..70ed0ef046
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/smallTargets/SmallThree.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Rectangle {
+ width: 100; height: 100
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "red" }
+ GradientStop { position: 0.33; color: "yellow" }
+ GradientStop { position: 1.0; color: "green" }
+ }
+}
diff --git a/tests/benchmarks/declarative/holistic/data/smallTargets/SmallTwo.qml b/tests/benchmarks/declarative/holistic/data/smallTargets/SmallTwo.qml
new file mode 100644
index 0000000000..c473ce53a6
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/data/smallTargets/SmallTwo.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Rectangle {
+ width: 100
+ height: 100
+ color: "blue"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+}
diff --git a/tests/benchmarks/declarative/holistic/holistic.pro b/tests/benchmarks/declarative/holistic/holistic.pro
new file mode 100644
index 0000000000..7f27696d60
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/holistic.pro
@@ -0,0 +1,19 @@
+load(qttest_p4)
+TEMPLATE = app
+TARGET = tst_holistic
+QT += declarative script network
+macx:CONFIG -= app_bundle
+
+CONFIG += release
+
+SOURCES += tst_holistic.cpp \
+ testtypes.cpp
+HEADERS += testtypes.h
+
+symbian {
+ data.files += data
+ data.path = .
+ DEPLOYMENT += data
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD\\\"
+}
diff --git a/tests/benchmarks/declarative/holistic/testtypes.cpp b/tests/benchmarks/declarative/holistic/testtypes.cpp
new file mode 100644
index 0000000000..5c232430f7
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/testtypes.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "testtypes.h"
+#include <QWidget>
+#include <QPlainTextEdit>
+#include <QDeclarativeEngine>
+#include <QScriptEngine>
+
+static QScriptValue script_api(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ static int testProperty = 13;
+ QScriptValue v = scriptEngine->newObject();
+ v.setProperty("scriptTestProperty", testProperty++);
+ return v;
+}
+
+static QObject *qobject_api(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ testQObjectApi *o = new testQObjectApi();
+ o->setQObjectTestProperty(20);
+ return o;
+}
+
+static QObject *qobject_api_engine_parent(QDeclarativeEngine *engine, QScriptEngine *scriptEngine)
+{
+ Q_UNUSED(scriptEngine)
+
+ static int testProperty = 26;
+ testQObjectApi *o = new testQObjectApi(engine);
+ o->setQObjectTestProperty(testProperty++);
+ return o;
+}
+
+void registerTypes()
+{
+ qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObjectAlias");
+ qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObject");
+
+ qmlRegisterType<QPlainTextEdit>("Qt.test",1,0,"QPlainTextEdit");
+ qRegisterMetaType<MyQmlObject::MyType>("MyQmlObject::MyType");
+
+ qmlRegisterType<ScarceResourceProvider>("Qt.test", 1,0, "MyScarceResourceProvider");
+ qmlRegisterType<ArbitraryVariantProvider>("Qt.test", 1,0, "MyArbitraryVariantProvider");
+
+ qmlRegisterModuleApi("Qt.test",1,0,script_api); // register (script) module API for an existing uri which contains elements
+ qmlRegisterModuleApi("Qt.test",1,0,qobject_api); // register (qobject) for an existing uri for which another module API was previously regd. Should replace!
+ qmlRegisterModuleApi("Qt.test.scriptApi",1,0,script_api); // register (script) module API for a uri which doesn't contain elements
+ qmlRegisterModuleApi("Qt.test.qobjectApi",1,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements
+ qmlRegisterModuleApi("Qt.test.qobjectApi",1,3,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, minor version set
+ qmlRegisterModuleApi("Qt.test.qobjectApi",2,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, major version set
+ qmlRegisterModuleApi("Qt.test.qobjectApiParented",1,0,qobject_api_engine_parent); // register (parented qobject) module API for a uri which doesn't contain elements
+}
+
+//#include "testtypes.moc"
diff --git a/tests/benchmarks/declarative/holistic/testtypes.h b/tests/benchmarks/declarative/holistic/testtypes.h
new file mode 100644
index 0000000000..e3e0ffa482
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/testtypes.h
@@ -0,0 +1,355 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef TESTTYPES_H
+#define TESTTYPES_H
+
+#include <QtCore/qobject.h>
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qsize.h>
+#include <QtDeclarative/qdeclarativelist.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qmatrix.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qvector3d.h>
+#include <QtCore/qdatetime.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qdeclarativescriptstring.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+
+class MyQmlAttachedObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value CONSTANT)
+ Q_PROPERTY(int value2 READ value2 WRITE setValue2)
+public:
+ MyQmlAttachedObject(QObject *parent) : QObject(parent), m_value2(0) {}
+
+ int value() const { return 19; }
+ int value2() const { return m_value2; }
+ void setValue2(int v) { m_value2 = v; }
+
+ void emitMySignal() { emit mySignal(); }
+
+signals:
+ void mySignal();
+
+private:
+ int m_value2;
+};
+
+class MyQmlObject : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(MyEnum)
+ Q_ENUMS(MyEnum2)
+ Q_PROPERTY(int deleteOnSet READ deleteOnSet WRITE setDeleteOnSet)
+ Q_PROPERTY(bool trueProperty READ trueProperty CONSTANT)
+ Q_PROPERTY(bool falseProperty READ falseProperty CONSTANT)
+ Q_PROPERTY(int value READ value WRITE setValue)
+ Q_PROPERTY(int console READ console CONSTANT)
+ Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged)
+ Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QObject> objectListProperty READ objectListProperty CONSTANT)
+ Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty)
+ Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp)
+ Q_PROPERTY(int nonscriptable READ nonscriptable WRITE setNonscriptable SCRIPTABLE false)
+
+public:
+ MyQmlObject(): myinvokableObject(0), m_methodCalled(false), m_methodIntCalled(false), m_object(0), m_value(0), m_resetProperty(13) {}
+
+ enum MyEnum { EnumValue1 = 0, EnumValue2 = 1 };
+ enum MyEnum2 { EnumValue3 = 2, EnumValue4 = 3 };
+
+ bool trueProperty() const { return true; }
+ bool falseProperty() const { return false; }
+
+ QString stringProperty() const { return m_string; }
+ void setStringProperty(const QString &s)
+ {
+ if (s == m_string)
+ return;
+ m_string = s;
+ emit stringChanged();
+ }
+
+ QObject *objectProperty() const { return m_object; }
+ void setObjectProperty(QObject *obj) {
+ if (obj == m_object)
+ return;
+ m_object = obj;
+ emit objectChanged();
+ }
+
+ QDeclarativeListProperty<QObject> objectListProperty() { return QDeclarativeListProperty<QObject>(this, m_objectQList); }
+
+ bool methodCalled() const { return m_methodCalled; }
+ bool methodIntCalled() const { return m_methodIntCalled; }
+
+ QString string() const { return m_string; }
+
+ static MyQmlAttachedObject *qmlAttachedProperties(QObject *o) {
+ return new MyQmlAttachedObject(o);
+ }
+
+ int deleteOnSet() const { return 1; }
+ void setDeleteOnSet(int v) { if(v) delete this; }
+
+ int value() const { return m_value; }
+ void setValue(int v) { m_value = v; }
+
+ int resettableProperty() const { return m_resetProperty; }
+ void setResettableProperty(int v) { m_resetProperty = v; }
+ void resetProperty() { m_resetProperty = 13; }
+
+ QRegExp regExp() { return m_regExp; }
+ void setRegExp(const QRegExp &regExp) { m_regExp = regExp; }
+
+ int console() const { return 11; }
+
+ int nonscriptable() const { return 0; }
+ void setNonscriptable(int) {}
+
+ MyQmlObject *myinvokableObject;
+ Q_INVOKABLE MyQmlObject *returnme() { return this; }
+
+ struct MyType {
+ int value;
+ };
+ QVariant variant() const { return m_variant; }
+
+signals:
+ void basicSignal();
+ void argumentSignal(int a, QString b, qreal c);
+ void stringChanged();
+ void objectChanged();
+ void anotherBasicSignal();
+ void thirdBasicSignal();
+ void signalWithUnknownType(const MyQmlObject::MyType &arg);
+
+public slots:
+ void deleteMe() { delete this; }
+ void methodNoArgs() { m_methodCalled = true; }
+ void method(int a) { if(a == 163) m_methodIntCalled = true; }
+ void setString(const QString &s) { m_string = s; }
+ void myinvokable(MyQmlObject *o) { myinvokableObject = o; }
+ void variantMethod(const QVariant &v) { m_variant = v; }
+
+private:
+ friend class tst_qdeclarativeecmascript;
+ bool m_methodCalled;
+ bool m_methodIntCalled;
+
+ QObject *m_object;
+ QString m_string;
+ QList<QObject *> m_objectQList;
+ int m_value;
+ int m_resetProperty;
+ QRegExp m_regExp;
+ QVariant m_variant;
+};
+
+QML_DECLARE_TYPEINFO(MyQmlObject, QML_HAS_ATTACHED_PROPERTIES)
+Q_DECLARE_METATYPE(MyQmlObject::MyType)
+
+class testQObjectApi : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY (int qobjectTestProperty READ qobjectTestProperty NOTIFY qobjectTestPropertyChanged)
+
+public:
+ testQObjectApi(QObject* parent = 0)
+ : QObject(parent), m_testProperty(0)
+ {
+ }
+
+ ~testQObjectApi() {}
+
+ int qobjectTestProperty() const { return m_testProperty; }
+ void setQObjectTestProperty(int tp) { m_testProperty = tp; emit qobjectTestPropertyChanged(tp); }
+
+signals:
+ void qobjectTestPropertyChanged(int testProperty);
+
+private:
+ int m_testProperty;
+};
+
+class ArbitraryVariantProvider : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant arbitraryVariant READ arbitraryVariant WRITE setArbitraryVariant NOTIFY arbitraryVariantChanged)
+
+public:
+ ArbitraryVariantProvider(QObject *parent = 0)
+ : QObject(parent), m_value(QVariant(QString(QLatin1String("random string value")))), m_count(1)
+ {
+ }
+
+ ~ArbitraryVariantProvider() {}
+
+ // the variant provided by the provider
+ QVariant arbitraryVariant() const { return m_value; }
+ void setArbitraryVariant(const QVariant& value) { m_value = value; emit arbitraryVariantChanged(); }
+ Q_INVOKABLE int changeVariant()
+ {
+ QPixmap pv(150, 150);
+ pv.fill(Qt::green);
+ int choice = qrand() % 4;
+ switch (choice) {
+ case 0: setArbitraryVariant(QVariant(QString(QLatin1String("string variant value")))); break;
+ case 1: setArbitraryVariant(QVariant(QColor(110, 120, 130))); break;
+ case 2: setArbitraryVariant(QVariant(55)); break;
+ default: setArbitraryVariant(QVariant(pv)); break;
+ }
+
+ m_count += 1;
+ return m_count;
+ }
+ Q_INVOKABLE QVariant setVariantToFilledPixmap(int width, int height, int r, int g, int b)
+ {
+ QPixmap pv(width % 300, height % 300);
+ pv.fill(QColor(r % 256, g % 256, b % 256));
+ m_value = pv;
+ m_count += 1;
+ return m_value;
+ }
+ Q_INVOKABLE QVariant setVariantAddCount(int addToCount, const QVariant& newValue)
+ {
+ m_value = newValue;
+ m_count += addToCount;
+ return m_value;
+ }
+ Q_INVOKABLE QVariant possibleVariant(int randomFactorOne, int randomFactorTwo, int randomFactorThree) const
+ {
+ QVariant retn;
+ QPixmap pv(randomFactorOne % 300, randomFactorTwo % 300);
+ pv.fill(QColor(randomFactorOne % 256, randomFactorTwo % 256, randomFactorThree % 256));
+ int choice = qrand() % 4;
+ switch (choice) {
+ case 0: retn = QVariant(QString(QLatin1String("string variant value"))); break;
+ case 1: retn = QVariant(QColor(randomFactorThree % 256, randomFactorTwo % 256, randomFactorOne % 256)); break;
+ case 2: retn = QVariant((55 + randomFactorThree)); break;
+ default: retn = QVariant(pv); break;
+ }
+ return retn;
+ }
+
+ // the following functions cover permutations of return value and arguments.
+ // functions with no return value:
+ Q_INVOKABLE void doNothing() const { /* does nothing */ } // no args, const
+ Q_INVOKABLE void incrementVariantChangeCount() { m_count = m_count + 1; } // no args, nonconst
+ Q_INVOKABLE void doNothing(int) const { /* does nothing. */ } // arg, const
+ Q_INVOKABLE void setVariantChangeCount(int newCount) { m_count = newCount; } // arg, nonconst
+ // functions with return value:
+ Q_INVOKABLE int variantChangeCount() const { return m_count; } // no args, const
+ Q_INVOKABLE int modifyVariantChangeCount() { m_count += 3; return m_count; } // no args, nonconst
+ Q_INVOKABLE int countPlus(int value) const { return m_count + value; } // arg, const
+ Q_INVOKABLE int modifyVariantChangeCount(int modifier) { m_count += modifier; return m_count; } // arg, nonconst.
+
+signals:
+ void arbitraryVariantChanged();
+
+private:
+ QVariant m_value;
+ int m_count;
+};
+
+class ScarceResourceProvider : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QPixmap smallScarceResource READ smallScarceResource WRITE setSmallScarceResource NOTIFY smallScarceResourceChanged)
+ Q_PROPERTY(QPixmap largeScarceResource READ largeScarceResource WRITE setLargeScarceResource NOTIFY largeScarceResourceChanged)
+
+public:
+ ScarceResourceProvider(QObject *parent = 0)
+ : QObject(parent), m_small(100, 100), m_large(1000, 1000), m_colour(1)
+ {
+ m_small.fill(Qt::blue);
+ m_large.fill(Qt::blue);
+ }
+
+ ~ScarceResourceProvider() {}
+
+ QPixmap smallScarceResource() const { return m_small; }
+ void setSmallScarceResource(QPixmap v) { m_small = v; emit smallScarceResourceChanged(); }
+ bool smallScarceResourceIsDetached() const { return m_small.isDetached(); }
+
+ QPixmap largeScarceResource() const { return m_large; }
+ void setLargeScarceResource(QPixmap v) { m_large = v; emit largeScarceResourceChanged(); }
+ bool largeScarceResourceIsDetached() const { return m_large.isDetached(); }
+
+ Q_INVOKABLE void changeResources()
+ {
+ QPixmap newSmall(100, 100);
+ QPixmap newLarge(1000, 1000);
+
+ if (m_colour == 1) {
+ m_colour = 2;
+ newSmall.fill(Qt::red);
+ newLarge.fill(Qt::red);
+ } else {
+ m_colour = 1;
+ newSmall.fill(Qt::blue);
+ newLarge.fill(Qt::blue);
+ }
+
+ setSmallScarceResource(newSmall);
+ setLargeScarceResource(newLarge);
+ }
+
+signals:
+ void smallScarceResourceChanged();
+ void largeScarceResourceChanged();
+
+private:
+ QPixmap m_small;
+ QPixmap m_large;
+
+ int m_colour;
+};
+
+void registerTypes();
+
+#endif // TESTTYPES_H
+
diff --git a/tests/benchmarks/declarative/holistic/tst_holistic.cpp b/tests/benchmarks/declarative/holistic/tst_holistic.cpp
new file mode 100644
index 0000000000..63dc11fc4b
--- /dev/null
+++ b/tests/benchmarks/declarative/holistic/tst_holistic.cpp
@@ -0,0 +1,612 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testtypes.h"
+
+#include <qtest.h>
+#include <QDeclarativeEngine>
+#include <QDeclarativeComponent>
+#include <QDeclarativeContext>
+#include <QDeclarativeProperty>
+#include <QFile>
+#include <QDebug>
+
+#ifdef Q_OS_SYMBIAN
+// In Symbian OS test data is located in applications private dir
+#define SRCDIR "."
+#endif
+
+// Conceptually, there are several different "holistic" areas to benchmark:
+// 1) Loading
+// - read file from disk
+// - parse/lex file
+// - handle nested imports
+// 2) Compilation
+// - create meta object templates etc
+// - compile to bytecode and cache it
+// 3) Instantiation
+// - running the bytecode to create an object tree, assign properties, etc
+// - and, importantly, to evaluate bindings for the first time (incl. js expressions)
+// 4) Dynamicism
+// - bindings evaluation
+// - signal handlers
+//
+// Aside from this, we also need to determine:
+// 1) JavaScript Metrics
+// - simple expressions
+// - complex expressions
+// - instantiation vs evaluation time
+// - imports and nested imports
+// 2) Context-switch costs
+// - how expensive is it to call a cpp function from QML
+// - how expensive is it to call a js function from cpp via QML
+// - how expensive is it to pass around objects between them
+// 3) Complete creation time.
+// - loading + compilation + instantiation (for "application startup time" metric)
+//
+// In some cases, we want to include "initialization costs";
+// i.e., we need to tell the engine not to cache type data resulting
+// in compilation between rounds, and we need to tell the engine not
+// to cache whatever it caches between instantiations of components.
+// The reason for this is that it is often the "first start of application"
+// performance which we're attempting to benchmark.
+
+// define some custom types we use in test data functions.
+typedef QList<QString> PropertyNameList;
+Q_DECLARE_METATYPE(PropertyNameList);
+typedef QList<QVariant> PropertyValueList;
+Q_DECLARE_METATYPE(PropertyValueList);
+
+class tst_holistic : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_holistic();
+
+private slots:
+ void initTestCase()
+ {
+ registerTypes();
+ qRegisterMetaType<PropertyNameList>("PropertyNameList");
+ qRegisterMetaType<PropertyValueList>("PropertyValueList");
+ }
+
+ void compilation_data();
+ void compilation();
+ void instantiation_data() { compilation_data(); }
+ void instantiation();
+ void creation_data() { compilation_data(); }
+ void creation();
+ void dynamicity_data();
+ void dynamicity();
+
+ void cppToJsDirect_data();
+ void cppToJsDirect();
+ void cppToJsIndirect();
+
+ void typeResolution_data();
+ void typeResolution();
+
+private:
+ QDeclarativeEngine engine;
+};
+
+tst_holistic::tst_holistic()
+{
+}
+
+inline QUrl TEST_FILE(const QString &filename)
+{
+ return QUrl::fromLocalFile(QLatin1String(SRCDIR) + QLatin1String("/data/") + filename);
+}
+
+
+void tst_holistic::compilation_data()
+{
+ QTest::addColumn<QStringList>("files");
+ QTest::addColumn<int>("repetitions");
+
+ QStringList f;
+
+ // Benchmarks: a single, small component once with no caching.
+ f << QString(SRCDIR + QLatin1String("/data/smallTargets/SmallOne.qml"));
+ QTest::newRow("single small component") << f << 1;
+
+ // Benchmarks: a single, small component ten times with caching.
+ QTest::newRow("single small component cached") << f << 10; f.clear();
+
+ // Benchmarks: a single, large component once with no caching.
+ f << QString(SRCDIR + QLatin1String("/data/largeTargets/mousearea-example.qml"));
+ QTest::newRow("single large component") << f << 1;
+
+ // Benchmarks: a single, large component ten times with caching.
+ QTest::newRow("single large component cached") << f << 10; f.clear();
+
+ // Benchmarks: 4 small components once each with no caching
+ f << QString(SRCDIR + QLatin1String("/data/smallTargets/SmallOne.qml"));
+ f << QString(SRCDIR + QLatin1String("/data/smallTargets/SmallTwo.qml"));
+ f << QString(SRCDIR + QLatin1String("/data/smallTargets/SmallThree.qml"));
+ f << QString(SRCDIR + QLatin1String("/data/smallTargets/SmallFour.qml"));
+ QTest::newRow("multiple small components") << f << 1;
+
+ // Benchmarks: 4 small components ten times each with caching
+ QTest::newRow("multiple small components cached") << f << 10; f.clear();
+
+ // Benchmarks: 3 large components once each with no caching.
+ f << QString(SRCDIR + QLatin1String("/data/largeTargets/mousearea-example.qml"));
+ f << QString(SRCDIR + QLatin1String("/data/largeTargets/gridview-example.qml"));
+ f << QString(SRCDIR + QLatin1String("/data/largeTargets/layoutdirection.qml"));
+ QTest::newRow("multiple large components") << f << 1;
+
+ // Benchmarks: 3 large components ten times each with caching.
+ QTest::newRow("multiple large components cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports a single small js file, no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/Sssi.qml"));
+ QTest::newRow("single small js import") << f << 1;
+
+ // Benchmarks: single small component which imports a single small js file, 10 reps, with caching
+ QTest::newRow("single small js import, cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports multiple small js files (no deep nesting), no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/Msbsi.qml"));
+ QTest::newRow("multiple small js imports, shallow") << f << 1;
+
+ // Benchmarks: single small component which imports multiple small js files (no deep nesting), 10 reps, with caching
+ QTest::newRow("multiple small js imports, shallow, cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports multiple small js files (with deep nesting), no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/Msdsi.qml"));
+ QTest::newRow("multiple small js imports, deeply nested") << f << 1;
+
+ // Benchmarks: single small component which imports multiple small js files (with deep nesting), 10 reps, with caching
+ QTest::newRow("multiple small js imports, deeply nested, cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports multiple small js files (nested and unnested), no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/Mssi.qml"));
+ QTest::newRow("muliple small js imports, both") << f << 1;
+
+ // Benchmarks: single small component which imports multiple small js files (nested and unnested), 10 reps, with caching
+ QTest::newRow("muliple small js imports, both, cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports a single large js file, no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/Slsi.qml"));
+ QTest::newRow("single large js import") << f << 1;
+
+ // Benchmarks: single small component which imports a single large js file, 10 reps, with caching
+ QTest::newRow("single large js import, cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports multiple large js files (no deep nesting), no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/Mlbsi.qml"));
+ QTest::newRow("multiple large js imports, shallow") << f << 1;
+
+ // Benchmarks: single small component which imports multiple large js files (no deep nesting), 10 reps, with caching
+ QTest::newRow("multiple large js imports, shallow, cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports multiple large js files (with deep nesting), no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/Mldsi.qml"));
+ QTest::newRow("multiple large js imports, deeply nested") << f << 1;
+
+ // Benchmarks: single small component which imports multiple large js files (with deep nesting), 10 reps, with caching
+ QTest::newRow("multiple large js imports, deeply nested, cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports multiple large js files (nested and unnested), no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/Mlsi.qml"));
+ QTest::newRow("multiple large js imports, both") << f << 1;
+
+ // Benchmarks: single small component which imports multiple large js files (nested and unnested), 10 reps, with caching
+ QTest::newRow("multiple large js imports, both, cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports multiple js files which all import a .pragma library js file, no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/PragmaBm.qml"));
+ QTest::newRow(".pragma library js import") << f << 1;
+
+ // Benchmarks: single small component which imports multiple js files which all import a .pragma library js file, 10 reps, with caching
+ QTest::newRow(".pragma library js import, cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports a js file which imports a QML module, no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/ModuleBm.qml"));
+ QTest::newRow("import js with QML import") << f << 1;
+
+ // Benchmarks: single small component which imports a js file which imports a QML module, 10 reps, with caching
+ QTest::newRow("import js with QML import, cached") << f << 10; f.clear();
+
+ // Benchmarks: single small component which imports multiple js files which all import a .pragma library js file and a QML module, no caching
+ f << QString(SRCDIR + QLatin1String("/data/jsImports/PragmaModuleBm.qml"));
+ QTest::newRow("import js with QML import and .pragma library") << f << 1;
+
+ // Benchmarks: single small component which imports multiple js files which all import a .pragma library js file and a QML module, 10 reps, with caching
+ QTest::newRow("import js with QML import and .pragma library, cached") << f << 10; f.clear();
+}
+
+void tst_holistic::compilation()
+{
+ // This function benchmarks the cost of loading and compiling specified QML files.
+ // If "repetitions" is non-zero, each file from "files" will be compiled "repetitions"
+ // times, without clearing the engine's component cache between compilations.
+
+ QFETCH(QStringList, files);
+ QFETCH(int, repetitions);
+ Q_ASSERT(files.size() > 0);
+ Q_ASSERT(repetitions > 0);
+
+ QBENCHMARK {
+ engine.clearComponentCache();
+ for (int i = 0; i < repetitions; ++i) {
+ for (int j = 0; j < files.size(); ++j) {
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(files.at(j)));
+ }
+ }
+ }
+}
+
+void tst_holistic::instantiation()
+{
+ // This function benchmarks the cost of instantiating components compiled from specified QML files.
+ // If "repetitions" is non-zero, each component compiled from "files" will be instantiated "repetitions"
+ // times, without clearing the component's instantiation cache between instantiations.
+
+ QFETCH(QStringList, files);
+ QFETCH(int, repetitions);
+ Q_ASSERT(files.size() > 0);
+ Q_ASSERT(repetitions > 0);
+
+ QList<QDeclarativeComponent*> components;
+ for (int i = 0; i < files.size(); ++i) {
+ QDeclarativeComponent *c = new QDeclarativeComponent(&engine, QUrl::fromLocalFile(files.at(i)));
+ components.append(c);
+ }
+
+ QBENCHMARK {
+ // XXX TODO: clear each component's instantiation cache
+
+ for (int i = 0; i < repetitions; ++i) {
+ for (int j = 0; j < components.size(); ++j) {
+ QObject *obj = components.at(j)->create();
+ delete obj;
+ }
+ }
+ }
+
+ // cleanup
+ for (int i = 0; i < components.size(); ++i) {
+ delete components.at(i);
+ }
+}
+
+void tst_holistic::creation()
+{
+ // This function benchmarks the cost of loading, compiling and instantiating specified QML files.
+ // If "repetitions" is non-zero, each file from "files" will be created "repetitions"
+ // times, without clearing the engine's component cache between component creation.
+
+ QFETCH(QStringList, files);
+ QFETCH(int, repetitions);
+ Q_ASSERT(files.size() > 0);
+ Q_ASSERT(repetitions > 0);
+
+ QBENCHMARK {
+ engine.clearComponentCache();
+ for (int i = 0; i < repetitions; ++i) {
+ for (int j = 0; j < files.size(); ++j) {
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(files.at(j)));
+ QObject *obj = c.create();
+ delete obj;
+ }
+ }
+ }
+}
+
+void tst_holistic::dynamicity_data()
+{
+ QTest::addColumn<QString>("file");
+ QTest::addColumn<QString>("writeProperty");
+ QTest::addColumn<QVariant>("writeValueOne");
+ QTest::addColumn<QVariant>("writeValueTwo");
+ QTest::addColumn<QString>("readProperty");
+
+ QString f;
+
+ // Benchmarks: single simple property binding
+ f = QString(SRCDIR + QLatin1String("/data/dynamicTargets/DynamicOne.qml"));
+ QTest::newRow("single simple property binding") << f << QString(QLatin1String("dynamicWidth")) << QVariant(300) << QVariant(500) << QString(QLatin1String("height"));
+
+ // Benchmarks: multiple simple property bindings in one component
+ f = QString(SRCDIR + QLatin1String("/data/dynamicTargets/DynamicTwo.qml"));
+ QTest::newRow("multiple simple property bindings") << f << QString(QLatin1String("dynamicWidth")) << QVariant(300) << QVariant(500) << QString(QLatin1String("dynamicWidth"));
+
+ // Benchmarks: single simple property binding plus onPropertyChanged slot
+ f = QString(SRCDIR + QLatin1String("/data/dynamicTargets/DynamicThree.qml"));
+ QTest::newRow("single simple plus slot") << f << QString(QLatin1String("dynamicWidth")) << QVariant(300) << QVariant(500) << QString(QLatin1String("dynamicWidth"));
+
+ // Benchmarks: multiple simple property bindings plus multiple onPropertyChanged slots in one component
+ f = QString(SRCDIR + QLatin1String("/data/dynamicTargets/DynamicFour.qml"));
+ QTest::newRow("multiple simple plus slots") << f << QString(QLatin1String("dynamicWidth")) << QVariant(300) << QVariant(500) << QString(QLatin1String("dynamicHeight"));
+
+ // Benchmarks: single simple js expression in a slot
+ f = QString(SRCDIR + QLatin1String("/data/jsTargets/JsOne.qml"));
+ QTest::newRow("single simple js expression slot") << f << QString(QLatin1String("dynamicWidth")) << QVariant(300) << QVariant(500) << QString(QLatin1String("dynamicWidth"));
+
+ // Benchmarks: single complex js expression in a slot
+ f = QString(SRCDIR + QLatin1String("/data/jsTargets/JsTwo.qml"));
+ QTest::newRow("single complex js expression slot") << f << QString(QLatin1String("dynamicWidth")) << QVariant(300) << QVariant(500) << QString(QLatin1String("dynamicWidth"));
+
+ // Benchmarks: simple property assignment and bindings update
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/CppToQml.qml"));
+ QTest::newRow("single simple property binding") << f << QString(QLatin1String("arbitrary")) << QVariant(36) << QVariant(35) << QString(QLatin1String("arbitrary"));
+}
+
+void tst_holistic::dynamicity()
+{
+ // This function benchmarks the cost of "continued operation" - signal invocation,
+ // updating bindings, etc. Note that we take two different writeValues in order
+ // to force updates to occur, and we read to force lazy evaluation to occur.
+
+ QFETCH(QString, file);
+ QFETCH(QString, writeProperty);
+ QFETCH(QVariant, writeValueOne);
+ QFETCH(QVariant, writeValueTwo);
+ QFETCH(QString, readProperty);
+
+ QDeclarativeComponent c(&engine, file);
+ QObject *obj = c.create();
+
+ QVariant readValue;
+ QVariant writeValue;
+ bool usedFirst = false;
+
+ QBENCHMARK {
+ if (usedFirst) {
+ writeValue = writeValueTwo;
+ usedFirst = false;
+ } else {
+ writeValue = writeValueOne;
+ usedFirst = true;
+ }
+
+ obj->setProperty(writeProperty.toAscii().constData(), writeValue);
+ readValue = obj->property(readProperty.toAscii().constData());
+ }
+
+ delete obj;
+}
+
+
+
+
+
+
+
+void tst_holistic::cppToJsDirect_data()
+{
+ QTest::addColumn<QString>("file");
+ QTest::addColumn<QString>("methodName");
+
+ QString f;
+
+ // Benchmarks: cost of calling a js function from cpp directly
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/CppToJs.qml"));
+ QTest::newRow("cpp-to-js") << f << QString(QLatin1String("callJsFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // const CPP function with no return value and no arguments.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppOne.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: no retn, no args") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // nonconst CPP function with no return value and no arguments.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppTwo.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: nonconst, no retn, no args") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // const CPP function with no return value and a single integer argument.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppThree.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: const, no retn, int arg") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // nonconst CPP function with no return value and a single integer argument.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppFour.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: nonconst, no retn, int arg") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // const CPP function with an integer return value and no arguments.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppFive.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: const, int retn, no args") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // nonconst CPP function with an integer return value and no arguments.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppSix.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: nonconst, int retn, no args") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // const CPP function with an integer return value and a single integer argument.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppSeven.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: const, int retn, int arg") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // nonconst CPP function with an integer return value and a single integer argument.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppEight.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: nonconst, int retn, int arg") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // const CPP function with a variant return value and multiple integer arguments.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppNine.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: const, variant retn, int args") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // nonconst CPP function with a variant return value and multiple integer arguments.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppTen.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: nonconst, variant retn, int args") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: cost of calling js function which calls cpp function:
+ // nonconst CPP function with a variant return value and multiple integer arguments.
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/JsToCppEleven.qml"));
+ QTest::newRow("cpp-to-js-to-cpp: nonconst, variant retn, variant + int args") << f << QString(QLatin1String("callCppFunction"));
+
+ // Benchmarks: calling js function which copies scarce resources by calling back into cpp scope
+ f = QString(SRCDIR + QLatin1String("/data/scopeSwitching/ScarceOne.qml"));
+ QTest::newRow("cpp-to-js-to-coo: copy scarce resources") << f << QString(QLatin1String("copyScarceResources"));
+}
+
+
+void tst_holistic::cppToJsDirect()
+{
+ // This function benchmarks the cost of calling from CPP scope to JS scope
+ // (and possibly vice versa, if the invoked js method then calls to cpp).
+
+ QFETCH(QString, file);
+ QFETCH(QString, methodName);
+
+ QDeclarativeComponent c(&engine, file);
+ QObject *obj = c.create();
+
+ QBENCHMARK {
+ QMetaObject::invokeMethod(obj, methodName.toLatin1().constData());
+ }
+
+ delete obj;
+}
+
+
+void tst_holistic::cppToJsIndirect()
+{
+ // This function benchmarks the cost of binding scarce resources
+ // to properties of a QML component. The engine should automatically release such
+ // resources when they are no longer used.
+ // The benchmark deliberately causes change signals to be emitted (and
+ // modifies the scarce resources) so that the properties are updated.
+
+ QDeclarativeComponent c(&engine, QString(SRCDIR + QLatin1String("/data/scopeSwitching/ScarceTwo.qml")));
+ QObject *obj = c.create();
+
+ ScarceResourceProvider *srp = 0;
+ srp = qobject_cast<ScarceResourceProvider*>(QDeclarativeProperty::read(obj, "a").value<QObject*>());
+
+ QBENCHMARK {
+ srp->changeResources(); // will cause small+large scarce resources changed signals to be emitted.
+ }
+
+ delete obj;
+}
+
+
+
+
+
+void tst_holistic::typeResolution_data()
+{
+ QTest::addColumn<QString>("file");
+ QTest::addColumn<PropertyNameList>("propertyNameOne");
+ QTest::addColumn<PropertyValueList>("propertyValueOne");
+ QTest::addColumn<PropertyNameList>("propertyNameTwo");
+ QTest::addColumn<PropertyValueList>("propertyValueTwo");
+ QTest::addColumn<int>("repetitions");
+
+ QString f;
+ PropertyNameList pn1;
+ PropertyValueList pv1;
+ PropertyNameList pn2;
+ PropertyValueList pv2;
+
+ // Benchmarks: resolving nested ids and types, no caching
+ f = QString(SRCDIR + QLatin1String("/data/resolutionTargets/ResolveOne.qml"));
+ pn1 << QString(QLatin1String("baseWidth")) << QString(QLatin1String("baseHeight")) << QString(QLatin1String("baseColor"));
+ pv1 << QVariant(401) << QVariant(402) << QVariant(QString(QLatin1String("brown")));
+ pn2 << QString(QLatin1String("baseWidth")) << QString(QLatin1String("baseHeight")) << QString(QLatin1String("baseColor"));
+ pv2 << QVariant(403) << QVariant(404) << QVariant(QString(QLatin1String("orange")));
+ QTest::newRow("nested id resolution") << f << pn1 << pv1 << pn2 << pv2 << 1;
+
+ // Benchmarks: resolving nested ids and types, 10 reps with caching
+ QTest::newRow("nested id resolution, cached") << f << pn1 << pv1 << pn2 << pv2 << 10;
+ pn1.clear(); pn2.clear(); pv1.clear(); pv2.clear();
+}
+
+void tst_holistic::typeResolution()
+{
+ // This function benchmarks the cost of "continued operation" (signal invocation,
+ // updating bindings, etc) where the component has lots of nested items with
+ // lots of resolving required. Note that we take two different writeValues in order
+ // to force updates to occur.
+
+ QFETCH(QString, file);
+ QFETCH(PropertyNameList, propertyNameOne);
+ QFETCH(PropertyValueList, propertyValueOne);
+ QFETCH(PropertyNameList, propertyNameTwo);
+ QFETCH(PropertyValueList, propertyValueTwo);
+ QFETCH(int, repetitions);
+
+ Q_ASSERT(propertyNameOne.size() == propertyValueOne.size());
+ Q_ASSERT(propertyNameTwo.size() == propertyValueTwo.size());
+ Q_ASSERT(repetitions > 0);
+
+ QDeclarativeComponent c(&engine, file);
+ QObject *obj = c.create();
+
+ PropertyNameList writeProperty;
+ PropertyValueList writeValue;
+ bool usedFirst = false;
+
+ QBENCHMARK {
+ for (int i = 0; i < repetitions; ++i) {
+ if (usedFirst) {
+ writeProperty = propertyNameOne;
+ writeValue = propertyValueOne;
+ usedFirst = false;
+ } else {
+ writeProperty = propertyNameTwo;
+ writeValue = propertyValueTwo;
+ usedFirst = true;
+ }
+
+ for (int j = 0; j < writeProperty.size(); ++j) {
+ obj->setProperty(writeProperty.at(j).toAscii().constData(), writeValue.at(j));
+ }
+ }
+ }
+
+ delete obj;
+}
+
+
+QTEST_MAIN(tst_holistic)
+
+#include "tst_holistic.moc"
diff --git a/tests/benchmarks/declarative/script/data/enums.qml b/tests/benchmarks/declarative/script/data/enums.qml
new file mode 100644
index 0000000000..81b27b9a58
--- /dev/null
+++ b/tests/benchmarks/declarative/script/data/enums.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+Item {
+ function runtest() {
+ var a = 0;
+ for (var ii = 0; ii < 100000; ++ii)
+ a += Text.RichText;
+ return a;
+ }
+}
diff --git a/tests/benchmarks/declarative/script/data/namespacedEnums.qml b/tests/benchmarks/declarative/script/data/namespacedEnums.qml
new file mode 100644
index 0000000000..dd3fa97de9
--- /dev/null
+++ b/tests/benchmarks/declarative/script/data/namespacedEnums.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0 as QtQuick
+
+QtQuick.Item {
+ function runtest() {
+ var a = 0;
+ for (var ii = 0; ii < 100000; ++ii)
+ a += QtQuick.Text.RichText;
+ return a;
+ }
+}
+
diff --git a/tests/benchmarks/declarative/script/data/script.js b/tests/benchmarks/declarative/script/data/script.js
new file mode 100644
index 0000000000..9f46570004
--- /dev/null
+++ b/tests/benchmarks/declarative/script/data/script.js
@@ -0,0 +1 @@
+function func() { return 1; }
diff --git a/tests/benchmarks/declarative/script/data/script2.js b/tests/benchmarks/declarative/script/data/script2.js
new file mode 100644
index 0000000000..102f081140
--- /dev/null
+++ b/tests/benchmarks/declarative/script/data/script2.js
@@ -0,0 +1,2 @@
+function func() { return 2; }
+
diff --git a/tests/benchmarks/declarative/script/data/scriptCall.qml b/tests/benchmarks/declarative/script/data/scriptCall.qml
new file mode 100644
index 0000000000..62014eb87a
--- /dev/null
+++ b/tests/benchmarks/declarative/script/data/scriptCall.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+import "script.js" as Script
+import "script2.js" as OtherScript
+
+Item {
+ function runtest() {
+ var a = 0;
+ for (var ii = 0; ii < 1000000; ++ii)
+ a += Script.func();
+ return a;
+ }
+}
+
diff --git a/tests/benchmarks/declarative/script/tst_script.cpp b/tests/benchmarks/declarative/script/tst_script.cpp
index 2020a18440..ff4bbb698e 100644
--- a/tests/benchmarks/declarative/script/tst_script.cpp
+++ b/tests/benchmarks/declarative/script/tst_script.cpp
@@ -70,6 +70,9 @@ private slots:
void property_qobject();
void property_qmlobject();
+ void setproperty_js();
+ void setproperty_qmlobject();
+
void function_js();
void function_cpp();
void function_qobject();
@@ -98,6 +101,10 @@ private slots:
void global_property_qml_js();
void scriptfile_property();
+
+ void enums();
+ void namespacedEnums();
+ void scriptCall();
};
inline QUrl TEST_FILE(const QString &filename)
@@ -108,12 +115,13 @@ inline QUrl TEST_FILE(const QString &filename)
class TestObject : public QObject
{
Q_OBJECT
- Q_PROPERTY(int x READ x)
+ Q_PROPERTY(int x READ x WRITE setX)
public:
TestObject(QObject *parent = 0);
int x();
+ void setX(int x) { m_x = x; }
void emitMySignal() { emit mySignal(); }
void emitMySignalWithArgs(int n) { emit mySignalWithArgs(n); }
@@ -323,6 +331,49 @@ void tst_script::property_qmlobject()
}
}
+#define SETPROPERTY_PROGRAM \
+ "(function(testObject) { return (function() { " \
+ " for (var ii = 0; ii < 10000; ++ii) { " \
+ " testObject.x = ii; " \
+ " } " \
+ "}); })"
+
+void tst_script::setproperty_js()
+{
+ QScriptEngine engine;
+
+ QScriptValue v = engine.newObject();
+ v.setProperty(QLatin1String("x"), 0);
+
+ QScriptValueList args;
+ args << v;
+ QScriptValue prog = engine.evaluate(SETPROPERTY_PROGRAM).call(engine.globalObject(), args);
+ prog.call();
+
+ QBENCHMARK {
+ prog.call();
+ }
+}
+
+void tst_script::setproperty_qmlobject()
+{
+ QDeclarativeEngine qmlengine;
+
+ QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(&qmlengine);
+ TestObject to;
+
+ QScriptValue v = QDeclarativeEnginePrivate::get(&qmlengine)->objectClass->newQObject(&to);
+
+ QScriptValueList args;
+ args << v;
+ QScriptValue prog = engine->evaluate(SETPROPERTY_PROGRAM).call(engine->globalObject(), args);
+ prog.call();
+
+ QBENCHMARK {
+ prog.call();
+ }
+}
+
#define FUNCTION_PROGRAM \
"(function(testObject) { return (function() { " \
" var test = 0; " \
@@ -698,6 +749,60 @@ void tst_script::scriptfile_property()
delete rect;
}
+void tst_script::enums()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, TEST_FILE("enums.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ int index = o->metaObject()->indexOfMethod("runtest()");
+ QVERIFY(index != -1);
+ QMetaMethod method = o->metaObject()->method(index);
+
+ QBENCHMARK {
+ method.invoke(o, Qt::DirectConnection);
+ }
+
+ delete o;
+}
+
+void tst_script::namespacedEnums()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, TEST_FILE("namespacedEnums.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ int index = o->metaObject()->indexOfMethod("runtest()");
+ QVERIFY(index != -1);
+ QMetaMethod method = o->metaObject()->method(index);
+
+ QBENCHMARK {
+ method.invoke(o, Qt::DirectConnection);
+ }
+
+ delete o;
+}
+
+void tst_script::scriptCall()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, TEST_FILE("scriptCall.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ int index = o->metaObject()->indexOfMethod("runtest()");
+ QVERIFY(index != -1);
+ QMetaMethod method = o->metaObject()->method(index);
+
+ QBENCHMARK {
+ method.invoke(o, Qt::DirectConnection);
+ }
+
+ delete o;
+}
+
QTEST_MAIN(tst_script)
#include "tst_script.moc"
diff --git a/tools/distfieldgen/distfieldgen.pro b/tools/distfieldgen/distfieldgen.pro
new file mode 100644
index 0000000000..4c2d63603b
--- /dev/null
+++ b/tools/distfieldgen/distfieldgen.pro
@@ -0,0 +1,12 @@
+TARGET = distfieldgen
+TEMPLATE = app
+
+QT += declarative opengl
+
+CONFIG += console
+CONFIG -= app_bundle
+DESTDIR = ../../bin
+
+INCLUDEPATH += $$PWD/../../src/3rdparty/harfbuzz/src
+
+SOURCES += main.cpp
diff --git a/tools/distfieldgen/main.cpp b/tools/distfieldgen/main.cpp
new file mode 100644
index 0000000000..3c944b3d4c
--- /dev/null
+++ b/tools/distfieldgen/main.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt scene graph research project.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <QtGui>
+
+#include <private/qsgdistancefieldglyphcache_p.h>
+
+static void usage()
+{
+ qWarning("Usage: distfieldgen [options] <font_filename>");
+ qWarning(" ");
+ qWarning("Distfieldgen generates distance-field renderings of the provided font file,");
+ qWarning("one for each font family/style it contains.");
+ qWarning("Unless the QT_QML_DISTFIELDDIR environment variable is set, the renderings are");
+ qWarning("saved in the fonts/distancefields directory where the Qt libraries are located.");
+ qWarning("You can also override the output directory with the -d option.");
+ qWarning(" ");
+ qWarning(" options:");
+ qWarning(" -d <directory>................................ output directory");
+ qWarning(" --no-multithread.............................. don't use multiple threads to render distance-fields");
+ qWarning(" --force-all-styles............................ force rendering of styles Normal, Bold, Italic and Bold Italic");
+ qWarning(" -styles \"style1,style2,..\".................... force rendering of specified styles");
+
+ qWarning(" ");
+ exit(1);
+}
+
+void printProgress(int p)
+{
+ printf("\r [");
+ for (int i = 0; i < 50; ++i)
+ printf(i < p / 2 ? "=" : " ");
+ printf("]");
+ printf(" %d%%", p);
+ fflush(stdout);
+}
+
+class DistFieldGenTask : public QRunnable
+{
+public:
+ DistFieldGenTask(QSGDistanceFieldGlyphCache *atlas, int c, int nbGlyph, QMap<int, QImage> *outList)
+ : QRunnable()
+ , m_atlas(atlas)
+ , m_char(c)
+ , m_nbGlyph(nbGlyph)
+ , m_outList(outList)
+ { }
+
+ void run()
+ {
+ QImage df = m_atlas->renderDistanceFieldGlyph(m_char);
+ QMutexLocker lock(&m_mutex);
+ m_outList->insert(m_char, df);
+ printProgress(float(m_outList->count()) / m_nbGlyph * 100);
+ }
+
+ static QMutex m_mutex;
+ QSGDistanceFieldGlyphCache *m_atlas;
+ int m_char;
+ int m_nbGlyph;
+ QMap<int, QImage> *m_outList;
+};
+
+QMutex DistFieldGenTask::m_mutex;
+
+static void generateDistanceFieldForFont(const QFont &font, const QString &destinationDir, bool multithread)
+{
+ QSGDistanceFieldGlyphCache *atlas = QSGDistanceFieldGlyphCache::get(QGLContext::currentContext(), font);
+ QFontDatabase db;
+ QString fontString = font.family() + QLatin1String(" ") + db.styleString(font);
+ qWarning("> Generating distance-field for font '%s' (%d glyphs)", fontString.toLatin1().constData(), atlas->glyphCount());
+
+ QMap<int, QImage> distfields;
+ for (int i = 0; i < atlas->glyphCount(); ++i) {
+ if (multithread) {
+ DistFieldGenTask *task = new DistFieldGenTask(atlas, i, atlas->glyphCount(), &distfields);
+ QThreadPool::globalInstance()->start(task);
+ } else {
+ QImage df = atlas->renderDistanceFieldGlyph(i);
+ distfields.insert(i, df);
+ printProgress(float(distfields.count()) / atlas->glyphCount() * 100);
+ }
+ }
+
+ if (multithread)
+ QThreadPool::globalInstance()->waitForDone();
+
+ // Combine dist fields in one image
+ int size = qCeil(qSqrt(qreal(atlas->glyphCount()))) * 64;
+ QImage output(size, size, QImage::Format_ARGB32_Premultiplied);
+ output.fill(Qt::transparent);
+ QPainter p(&output);
+ int x, y = 0;
+ for (QMap<int, QImage>::const_iterator i = distfields.constBegin(); i != distfields.constEnd(); ++i) {
+ p.drawImage(x, y, i.value());
+ x += 64;
+ if (x >= size) {
+ x = 0;
+ y += 64;
+ }
+ }
+ p.end();
+ printProgress(100);
+ printf("\n");
+
+ // Save output
+ QFileInfo dfi(destinationDir);
+ if (!dfi.isDir()) {
+ qWarning("Error: '%s' is not a directory.", destinationDir.toLatin1().constData());
+ qWarning(" ");
+ exit(1);
+ }
+
+ QString filename = font.family();
+ filename.remove(QLatin1String(" "));
+ QString italic = font.italic() ? QLatin1String("i") : QLatin1String("");
+ QString bold = font.weight() > QFont::Normal ? QLatin1String("b") : QLatin1String("");
+ filename = filename + bold + italic;
+ QString out = QString(QLatin1String("%1/%2.png")).arg(destinationDir).arg(filename);
+ output.save(out);
+ qWarning(" Distance-field saved to '%s'\n", out.toLatin1().constData());
+}
+
+class MyWidget : public QGLWidget
+{
+ Q_OBJECT
+public:
+ MyWidget()
+ : QGLWidget()
+ { }
+
+ ~MyWidget() { }
+
+ void showEvent(QShowEvent *e)
+ {
+ QStringList args = QApplication::arguments();
+
+ bool noMultithread = args.contains(QLatin1String("--no-multithread"));
+ bool forceAllStyles = args.contains(QLatin1String("--force-all-styles"));
+
+ QString fontFile;
+ QString destDir;
+ for (int i = 0; i < args.count(); ++i) {
+ QString a = args.at(i);
+ if (!a.startsWith('-') && QFileInfo(a).exists())
+ fontFile = a;
+ if (a == QLatin1String("-d"))
+ destDir = args.at(++i);
+ }
+ if (destDir.isEmpty()) {
+ destDir = QFileInfo(fontFile).canonicalPath();
+ }
+
+ QStringList customStyles;
+ if (args.contains(QLatin1String("-styles"))) {
+ int index = args.indexOf(QLatin1String("-styles"));
+ QString styles = args.at(index + 1);
+ customStyles = styles.split(QLatin1String(","));
+ }
+
+ // Load the font
+ int fontID = QFontDatabase::addApplicationFont(fontFile);
+ if (fontID == -1) {
+ qWarning("Error: Invalid font file.");
+ qWarning(" ");
+ exit(1);
+ }
+
+ QStringList allStyles = QStringList() << QLatin1String("Normal")
+ << QLatin1String("Bold")
+ << QLatin1String("Italic")
+ << QLatin1String("Bold Italic");
+
+ // Generate distance-fields for all families and all styles provided by the font file
+ QFontDatabase fontDatabase;
+ QStringList families = QFontDatabase::applicationFontFamilies(fontID);
+ int famCount = families.count();
+ for (int i = 0; i < famCount; ++i) {
+ QStringList styles;
+ if (forceAllStyles)
+ styles = allStyles;
+ else if (customStyles.count() > 0)
+ styles = customStyles;
+ else
+ styles = fontDatabase.styles(families.at(i));
+
+ int styleCount = styles.count();
+ for (int j = 0; j < styleCount; ++j) {
+ QFont font;
+ if (forceAllStyles || customStyles.count() > 0) {
+ int weight = styles.at(j).contains(QLatin1String("Bold")) ? QFont::Bold : QFont::Normal;
+ font = QFont(families.at(i), 10, weight, styles.at(j).contains(QLatin1String("Italic")));
+ } else {
+ font = fontDatabase.font(families.at(i), styles.at(j), 10); // point size is ignored
+ }
+ generateDistanceFieldForFont(font, destDir, !noMultithread);
+ }
+ }
+
+ exit(0);
+ }
+};
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QStringList args = QApplication::arguments();
+
+ if (argc < 2
+ || args.contains(QLatin1String("--help"))
+ || args.contains(QLatin1String("-help"))
+ || args.contains(QLatin1String("--h"))
+ || args.contains(QLatin1String("-h")))
+ usage();
+
+
+ MyWidget w;
+ w.show();
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/tools/qmlplugindump/Info.plist b/tools/qmlplugindump/Info.plist
new file mode 100644
index 0000000000..f35846d048
--- /dev/null
+++ b/tools/qmlplugindump/Info.plist
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>@TYPEINFO@</string>
+ <key>CFBundleExecutable</key>
+ <string>@EXECUTABLE@</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.nokia.qt.qmlplugindump</string>
+ <key>LSUIElement</key>
+ <string>1</string>
+</dict>
+</plist>
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
new file mode 100644
index 0000000000..848b0917cb
--- /dev/null
+++ b/tools/qmlplugindump/main.cpp
@@ -0,0 +1,597 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtDeclarative/QtDeclarative>
+#include <QtDeclarative/private/qdeclarativemetatype_p.h>
+#include <QtDeclarative/private/qdeclarativeopenmetaobject_p.h>
+#include <QtDeclarative/QDeclarativeView>
+
+#include <QtGui/QApplication>
+
+#include <QtCore/QSet>
+#include <QtCore/QMetaObject>
+#include <QtCore/QMetaProperty>
+#include <QtCore/QDebug>
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/private/qmetaobject_p.h>
+
+#include <iostream>
+
+#include "qmlstreamwriter.h"
+
+#ifdef QT_SIMULATOR
+#include <QtGui/private/qsimulatorconnection_p.h>
+#endif
+
+#ifdef Q_OS_UNIX
+#include <signal.h>
+#endif
+
+void collectReachableMetaObjects(const QMetaObject *meta, QSet<const QMetaObject *> *metas)
+{
+ if (! meta || metas->contains(meta))
+ return;
+
+ // dynamic meta objects break things badly, so just ignore them
+ const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(meta->d.data);
+ if (!(mop->flags & DynamicMetaObject))
+ metas->insert(meta);
+
+ collectReachableMetaObjects(meta->superClass(), metas);
+}
+
+QString currentProperty;
+
+void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *metas)
+{
+ if (! object)
+ return;
+
+ const QMetaObject *meta = object->metaObject();
+ qDebug() << "Processing object" << meta->className();
+ collectReachableMetaObjects(meta, metas);
+
+ for (int index = 0; index < meta->propertyCount(); ++index) {
+ QMetaProperty prop = meta->property(index);
+ if (QDeclarativeMetaType::isQObject(prop.userType())) {
+ qDebug() << " Processing property" << prop.name();
+ currentProperty = QString("%1::%2").arg(meta->className(), prop.name());
+
+ // if the property was not initialized during construction,
+ // accessing a member of oo is going to cause a segmentation fault
+ QObject *oo = QDeclarativeMetaType::toQObject(prop.read(object));
+ if (oo && !metas->contains(oo->metaObject()))
+ collectReachableMetaObjects(oo, metas);
+ currentProperty.clear();
+ }
+ }
+}
+
+void collectReachableMetaObjects(const QDeclarativeType *ty, QSet<const QMetaObject *> *metas)
+{
+ collectReachableMetaObjects(ty->metaObject(), metas);
+ if (ty->attachedPropertiesType())
+ collectReachableMetaObjects(ty->attachedPropertiesType(), metas);
+}
+
+/* We want to add the MetaObject for 'Qt' to the list, this is a
+ simple way to access it.
+*/
+class FriendlyQObject: public QObject
+{
+public:
+ static const QMetaObject *qtMeta() { return &staticQtMetaObject; }
+};
+
+/* When we dump a QMetaObject, we want to list all the types it is exported as.
+ To do this, we need to find the QDeclarativeTypes associated with this
+ QMetaObject.
+*/
+static QHash<QByteArray, QSet<const QDeclarativeType *> > qmlTypesByCppName;
+
+static QHash<QByteArray, QByteArray> cppToId;
+
+/* Takes a C++ type name, such as Qt::LayoutDirection or QString and
+ maps it to how it should appear in the description file.
+
+ These names need to be unique globally, so we don't change the C++ symbol's
+ name much. It is mostly used to for explicit translations such as
+ QString->string and translations for extended QML objects.
+*/
+QByteArray convertToId(const QByteArray &cppName)
+{
+ return cppToId.value(cppName, cppName);
+}
+
+QSet<const QMetaObject *> collectReachableMetaObjects(const QString &importCode, QDeclarativeEngine *engine)
+{
+ QSet<const QMetaObject *> metas;
+ metas.insert(FriendlyQObject::qtMeta());
+
+ QHash<QByteArray, QSet<QByteArray> > extensions;
+ foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
+ qmlTypesByCppName[ty->metaObject()->className()].insert(ty);
+ if (ty->isExtendedType()) {
+ extensions[ty->typeName()].insert(ty->metaObject()->className());
+ }
+ collectReachableMetaObjects(ty, &metas);
+ }
+
+ // Adjust ids of extended objects.
+ // The chain ends up being:
+ // __extended__.originalname - the base object
+ // __extension_0_.originalname - first extension
+ // ..
+ // __extension_n-2_.originalname - second to last extension
+ // originalname - last extension
+ // ### does this actually work for multiple extensions? it seems like the prototypes might be wrong
+ foreach (const QByteArray &extendedCpp, extensions.keys()) {
+ cppToId.remove(extendedCpp);
+ const QByteArray extendedId = convertToId(extendedCpp);
+ cppToId.insert(extendedCpp, "__extended__." + extendedId);
+ QSet<QByteArray> extensionCppNames = extensions.value(extendedCpp);
+ int c = 0;
+ foreach (const QByteArray &extensionCppName, extensionCppNames) {
+ if (c != extensionCppNames.size() - 1) {
+ QByteArray adjustedName = QString("__extension__%1.%2").arg(QString::number(c), QString(extendedId)).toAscii();
+ cppToId.insert(extensionCppName, adjustedName);
+ } else {
+ cppToId.insert(extensionCppName, extendedId);
+ }
+ ++c;
+ }
+ }
+
+ // find even more QMetaObjects by instantiating QML types and running
+ // over the instances
+ foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
+ if (ty->isExtendedType())
+ continue;
+
+ QByteArray tyName = ty->qmlTypeName();
+ tyName = tyName.mid(tyName.lastIndexOf('/') + 1);
+
+ QByteArray code = importCode.toUtf8();
+ code += tyName;
+ code += " {}\n";
+
+ QDeclarativeComponent c(engine);
+ c.setData(code, QUrl("typeinstance"));
+
+ QObject *object = c.create();
+ if (object)
+ collectReachableMetaObjects(object, &metas);
+ else
+ qDebug() << "Could not create" << tyName << ":" << c.errorString();
+ }
+
+ return metas;
+}
+
+
+class Dumper
+{
+ QmlStreamWriter *qml;
+ QString relocatableModuleUri;
+
+public:
+ Dumper(QmlStreamWriter *qml) : qml(qml) {}
+
+ void setRelocatableModuleUri(const QString &uri)
+ {
+ relocatableModuleUri = uri;
+ }
+
+ void dump(const QMetaObject *meta)
+ {
+ qml->writeStartObject("Component");
+
+ QByteArray id = convertToId(meta->className());
+ qml->writeScriptBinding(QLatin1String("name"), enquote(id));
+
+ for (int index = meta->classInfoCount() - 1 ; index >= 0 ; --index) {
+ QMetaClassInfo classInfo = meta->classInfo(index);
+ if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
+ qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(QLatin1String(classInfo.value())));
+ break;
+ }
+ }
+
+ if (meta->superClass())
+ qml->writeScriptBinding(QLatin1String("prototype"), enquote(convertToId(meta->superClass()->className())));
+
+ QSet<const QDeclarativeType *> qmlTypes = qmlTypesByCppName.value(meta->className());
+ if (!qmlTypes.isEmpty()) {
+ QStringList exports;
+
+ foreach (const QDeclarativeType *qmlTy, qmlTypes) {
+ QString qmlTyName = qmlTy->qmlTypeName();
+ // some qmltype names are missing the actual names, ignore that import
+ if (qmlTyName.endsWith('/'))
+ continue;
+ if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) {
+ qmlTyName.remove(0, relocatableModuleUri.size() + 1);
+ }
+ exports += enquote(QString("%1 %2.%3").arg(
+ qmlTyName,
+ QString::number(qmlTy->majorVersion()),
+ QString::number(qmlTy->minorVersion())));
+ }
+
+ // ensure exports are sorted and don't change order when the plugin is dumped again
+ exports.removeDuplicates();
+ qSort(exports);
+
+ qml->writeArrayBinding(QLatin1String("exports"), exports);
+
+ if (const QMetaObject *attachedType = (*qmlTypes.begin())->attachedPropertiesType()) {
+ qml->writeScriptBinding(QLatin1String("attachedType"), enquote(
+ convertToId(attachedType->className())));
+ }
+ }
+
+ for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
+ dump(meta->enumerator(index));
+
+ for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index)
+ dump(meta->property(index));
+
+ for (int index = meta->methodOffset(); index < meta->methodCount(); ++index)
+ dump(meta->method(index));
+
+ qml->writeEndObject();
+ }
+
+ void writeEasingCurve()
+ {
+ qml->writeStartObject("Component");
+ qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("QEasingCurve")));
+ qml->writeScriptBinding(QLatin1String("prototype"), enquote(QLatin1String("QDeclarativeEasingValueType")));
+ qml->writeEndObject();
+ }
+
+private:
+ static QString enquote(const QString &string)
+ {
+ return QString("\"%1\"").arg(string);
+ }
+
+ /* Removes pointer and list annotations from a type name, returning
+ what was removed in isList and isPointer
+ */
+ static void removePointerAndList(QByteArray *typeName, bool *isList, bool *isPointer)
+ {
+ static QByteArray declListPrefix = "QDeclarativeListProperty<";
+
+ if (typeName->endsWith('*')) {
+ *isPointer = true;
+ typeName->truncate(typeName->length() - 1);
+ removePointerAndList(typeName, isList, isPointer);
+ } else if (typeName->startsWith(declListPrefix)) {
+ *isList = true;
+ typeName->truncate(typeName->length() - 1); // get rid of the suffix '>'
+ *typeName = typeName->mid(declListPrefix.size());
+ removePointerAndList(typeName, isList, isPointer);
+ }
+
+ *typeName = convertToId(*typeName);
+ }
+
+ void writeTypeProperties(QByteArray typeName, bool isWritable)
+ {
+ bool isList = false, isPointer = false;
+ removePointerAndList(&typeName, &isList, &isPointer);
+
+ qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
+ if (isList)
+ qml->writeScriptBinding(QLatin1String("isList"), QLatin1String("true"));
+ if (!isWritable)
+ qml->writeScriptBinding(QLatin1String("isReadonly"), QLatin1String("true"));
+ if (isPointer)
+ qml->writeScriptBinding(QLatin1String("isPointer"), QLatin1String("true"));
+ }
+
+ void dump(const QMetaProperty &prop)
+ {
+ qml->writeStartObject("Property");
+
+ qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(prop.name())));
+ writeTypeProperties(prop.typeName(), prop.isWritable());
+
+ qml->writeEndObject();
+ }
+
+ void dump(const QMetaMethod &meth)
+ {
+ if (meth.methodType() == QMetaMethod::Signal) {
+ if (meth.access() != QMetaMethod::Protected)
+ return; // nothing to do.
+ } else if (meth.access() != QMetaMethod::Public) {
+ return; // nothing to do.
+ }
+
+ QByteArray name = meth.signature();
+ int lparenIndex = name.indexOf('(');
+ if (lparenIndex == -1) {
+ return; // invalid signature
+ }
+ name = name.left(lparenIndex);
+
+ if (meth.methodType() == QMetaMethod::Signal)
+ qml->writeStartObject(QLatin1String("Signal"));
+ else
+ qml->writeStartObject(QLatin1String("Method"));
+
+ qml->writeScriptBinding(QLatin1String("name"), enquote(name));
+
+ const QString typeName = convertToId(meth.typeName());
+ if (! typeName.isEmpty())
+ qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
+
+ for (int i = 0; i < meth.parameterTypes().size(); ++i) {
+ QByteArray argName = meth.parameterNames().at(i);
+
+ qml->writeStartObject(QLatin1String("Parameter"));
+ if (! argName.isEmpty())
+ qml->writeScriptBinding(QLatin1String("name"), enquote(argName));
+ writeTypeProperties(meth.parameterTypes().at(i), true);
+ qml->writeEndObject();
+ }
+
+ qml->writeEndObject();
+ }
+
+ void dump(const QMetaEnum &e)
+ {
+ qml->writeStartObject(QLatin1String("Enum"));
+ qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(e.name())));
+
+ QList<QPair<QString, QString> > namesValues;
+ for (int index = 0; index < e.keyCount(); ++index) {
+ namesValues.append(qMakePair(enquote(QString::fromUtf8(e.key(index))), QString::number(e.value(index))));
+ }
+
+ qml->writeScriptObjectLiteralBinding(QLatin1String("values"), namesValues);
+ qml->writeEndObject();
+ }
+};
+
+
+enum ExitCode {
+ EXIT_INVALIDARGUMENTS = 1,
+ EXIT_SEGV = 2,
+ EXIT_IMPORTERROR = 3
+};
+
+#ifdef Q_OS_UNIX
+void sigSegvHandler(int) {
+ fprintf(stderr, "Error: SEGV\n");
+ if (!currentProperty.isEmpty())
+ fprintf(stderr, "While processing the property '%s', which probably has uninitialized data.\n", currentProperty.toLatin1().constData());
+ exit(EXIT_SEGV);
+}
+#endif
+
+void printUsage(const QString &appName)
+{
+ qWarning() << qPrintable(QString(
+ "Usage: %1 [-notrelocatable] module.uri version [module/import/path]\n"
+ " %1 -path path/to/qmldir/directory [version]\n"
+ " %1 -builtins\n"
+ "Example: %1 Qt.labs.particles 4.7 /home/user/dev/qt-install/imports").arg(
+ appName));
+}
+
+int main(int argc, char *argv[])
+{
+#ifdef Q_OS_UNIX
+ // qmldump may crash, but we don't want any crash handlers to pop up
+ // therefore we intercept the segfault and just exit() ourselves
+ struct sigaction action;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = &sigSegvHandler;
+ action.sa_flags = 0;
+
+ sigaction(SIGSEGV, &action, 0);
+#endif
+
+#ifdef QT_SIMULATOR
+ // Running this application would bring up the Qt Simulator (since it links QtGui), avoid that!
+ QtSimulatorPrivate::SimulatorConnection::createStubInstance();
+#endif
+ QApplication app(argc, argv);
+ const QStringList args = app.arguments();
+ const QString appName = QFileInfo(app.applicationFilePath()).baseName();
+ if (!(args.size() >= 3
+ || (args.size() == 2
+ && (args.at(1) == QLatin1String("--builtins")
+ || args.at(1) == QLatin1String("-builtins"))))) {
+ printUsage(appName);
+ return EXIT_INVALIDARGUMENTS;
+ }
+
+ QString pluginImportUri;
+ QString pluginImportVersion;
+ QString pluginImportPath;
+ bool relocatable = true;
+ bool pathImport = false;
+ if (args.size() >= 3) {
+ QStringList positionalArgs;
+ foreach (const QString &arg, args) {
+ if (!arg.startsWith(QLatin1Char('-'))) {
+ positionalArgs.append(arg);
+ continue;
+ }
+
+ if (arg == QLatin1String("--notrelocatable")
+ || arg == QLatin1String("-notrelocatable")) {
+ relocatable = false;
+ } else if (arg == QLatin1String("--path")
+ || arg == QLatin1String("-path")) {
+ pathImport = true;
+ } else {
+ qWarning() << "Invalid argument: " << arg;
+ return EXIT_INVALIDARGUMENTS;
+ }
+ }
+
+ if (!pathImport) {
+ if (positionalArgs.size() != 3 && positionalArgs.size() != 4) {
+ qWarning() << "Incorrect number of positional arguments";
+ return EXIT_INVALIDARGUMENTS;
+ }
+ pluginImportUri = positionalArgs[1];
+ pluginImportVersion = positionalArgs[2];
+ if (positionalArgs.size() >= 4)
+ pluginImportPath = positionalArgs[3];
+ } else {
+ if (positionalArgs.size() != 2 && positionalArgs.size() != 3) {
+ qWarning() << "Incorrect number of positional arguments";
+ return EXIT_INVALIDARGUMENTS;
+ }
+ pluginImportPath = positionalArgs[1];
+ if (positionalArgs.size() == 3)
+ pluginImportVersion = positionalArgs[2];
+ }
+ }
+
+ QDeclarativeView view;
+ QDeclarativeEngine *engine = view.engine();
+ if (!pluginImportPath.isEmpty())
+ engine->addImportPath(pluginImportPath);
+
+ // find all QMetaObjects reachable from the builtin module
+ QByteArray importCode("import QtQuick 1.0\n");
+ QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(importCode, engine);
+
+ // this will hold the meta objects we want to dump information of
+ QSet<const QMetaObject *> metas;
+
+ if (pluginImportUri.isEmpty() && !pathImport) {
+ metas = defaultReachable;
+ } else {
+ // find all QMetaObjects reachable when the specified module is imported
+ if (!pathImport) {
+ importCode += QString("import %0 %1\n").arg(pluginImportUri, pluginImportVersion).toAscii();
+ } else {
+ // pluginImportVersion can be empty
+ importCode += QString("import \"%1\" %2\n").arg(pluginImportPath, pluginImportVersion).toAscii();
+ }
+
+ // create a component with these imports to make sure the imports are valid
+ // and to populate the declarative meta type system
+ {
+ QByteArray code = importCode;
+ code += "QtObject {}";
+ QDeclarativeComponent c(engine);
+
+ c.setData(code, QUrl("typelist"));
+ c.create();
+ if (!c.errors().isEmpty()) {
+ foreach (const QDeclarativeError &error, c.errors())
+ qWarning() << error.toString();
+ return EXIT_IMPORTERROR;
+ }
+ }
+
+ QSet<const QMetaObject *> candidates = collectReachableMetaObjects(importCode, engine);
+ candidates.subtract(defaultReachable);
+
+ // Also eliminate meta objects with the same classname.
+ // This is required because extended objects seem not to share
+ // a single meta object instance.
+ QSet<QByteArray> defaultReachableNames;
+ foreach (const QMetaObject *mo, defaultReachable)
+ defaultReachableNames.insert(QByteArray(mo->className()));
+ foreach (const QMetaObject *mo, candidates) {
+ if (!defaultReachableNames.contains(mo->className()))
+ metas.insert(mo);
+ }
+ }
+
+ // setup static rewrites of type names
+ cppToId.insert("QString", "string");
+ cppToId.insert("QDeclarativeEasingValueType::Type", "Type");
+
+ // start dumping data
+ QByteArray bytes;
+ QmlStreamWriter qml(&bytes);
+
+ qml.writeStartDocument();
+ qml.writeLibraryImport(QLatin1String("QtQuick.tooling"), 1, 0);
+ qml.write("\n"
+ "// This file describes the plugin-supplied types contained in the library.\n"
+ "// It is used for QML tooling purposes only.\n"
+ "\n");
+ qml.writeStartObject("Module");
+
+ // put the metaobjects into a map so they are always dumped in the same order
+ QMap<QString, const QMetaObject *> nameToMeta;
+ foreach (const QMetaObject *meta, metas)
+ nameToMeta.insert(convertToId(meta->className()), meta);
+
+ Dumper dumper(&qml);
+ if (relocatable)
+ dumper.setRelocatableModuleUri(pluginImportUri);
+ foreach (const QMetaObject *meta, nameToMeta) {
+ dumper.dump(meta);
+ }
+
+ // define QEasingCurve as an extension of QDeclarativeEasingValueType, this way
+ // properties using the QEasingCurve type get useful type information.
+ if (pluginImportUri.isEmpty())
+ dumper.writeEasingCurve();
+
+ qml.writeEndObject();
+ qml.writeEndDocument();
+
+ std::cout << bytes.constData();
+
+ // workaround to avoid crashes on exit
+ QTimer timer;
+ timer.setSingleShot(true);
+ timer.setInterval(0);
+ QObject::connect(&timer, SIGNAL(timeout()), &app, SLOT(quit()));
+ timer.start();
+
+ return app.exec();
+}
diff --git a/tools/qmlplugindump/qmlplugindump.pro b/tools/qmlplugindump/qmlplugindump.pro
new file mode 100644
index 0000000000..53827e2f40
--- /dev/null
+++ b/tools/qmlplugindump/qmlplugindump.pro
@@ -0,0 +1,20 @@
+TEMPLATE = app
+CONFIG += qt uic console
+DESTDIR = ../../bin
+
+QT += declarative
+
+TARGET = qmlplugindump
+
+SOURCES += \
+ main.cpp \
+ qmlstreamwriter.cpp
+
+HEADERS += \
+ qmlstreamwriter.h
+
+OTHER_FILES += Info.plist
+macx: QMAKE_INFO_PLIST = Info.plist
+
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
diff --git a/tools/qmlplugindump/qmlstreamwriter.cpp b/tools/qmlplugindump/qmlstreamwriter.cpp
new file mode 100644
index 0000000000..d083f7b64c
--- /dev/null
+++ b/tools/qmlplugindump/qmlstreamwriter.cpp
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlstreamwriter.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QStringList>
+
+QmlStreamWriter::QmlStreamWriter(QByteArray *array)
+ : m_indentDepth(0)
+ , m_pendingLineLength(0)
+ , m_maybeOneline(false)
+ , m_stream(new QBuffer(array))
+{
+ m_stream->open(QIODevice::WriteOnly);
+}
+
+void QmlStreamWriter::writeStartDocument()
+{
+}
+
+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());
+ if (!as.isEmpty())
+ m_stream->write(QString(" as %1").arg(as).toUtf8());
+ m_stream->write("\n");
+}
+
+void QmlStreamWriter::writeStartObject(const QString &component)
+{
+ flushPotentialLinesWithNewlines();
+ writeIndent();
+ m_stream->write(QString("%1 {").arg(component).toUtf8());
+ ++m_indentDepth;
+ m_maybeOneline = true;
+}
+
+void QmlStreamWriter::writeEndObject()
+{
+ if (m_maybeOneline && !m_pendingLines.isEmpty()) {
+ --m_indentDepth;
+ for (int i = 0; i < m_pendingLines.size(); ++i) {
+ m_stream->write(" ");
+ m_stream->write(m_pendingLines.at(i).trimmed());
+ if (i != m_pendingLines.size() - 1)
+ m_stream->write(";");
+ }
+ m_stream->write(" }\n");
+ m_pendingLines.clear();
+ m_pendingLineLength = 0;
+ m_maybeOneline = false;
+ } else {
+ if (m_maybeOneline)
+ flushPotentialLinesWithNewlines();
+ --m_indentDepth;
+ writeIndent();
+ m_stream->write("}\n");
+ }
+}
+
+void QmlStreamWriter::writeScriptBinding(const QString &name, const QString &rhs)
+{
+ writePotentialLine(QString("%1: %2").arg(name, rhs).toUtf8());
+}
+
+void QmlStreamWriter::writeArrayBinding(const QString &name, const QStringList &elements)
+{
+ flushPotentialLinesWithNewlines();
+ writeIndent();
+ m_stream->write(QString("%1: [\n").arg(name).toUtf8());
+ ++m_indentDepth;
+ for (int i = 0; i < elements.size(); ++i) {
+ writeIndent();
+ m_stream->write(elements.at(i).toUtf8());
+ if (i != elements.size() - 1) {
+ m_stream->write(",\n");
+ } else {
+ m_stream->write("\n");
+ }
+ }
+ --m_indentDepth;
+ writeIndent();
+ m_stream->write("]\n");
+}
+
+void QmlStreamWriter::write(const QString &data)
+{
+ flushPotentialLinesWithNewlines();
+ m_stream->write(data.toUtf8());
+}
+
+void QmlStreamWriter::writeScriptObjectLiteralBinding(const QString &name, const QList<QPair<QString, QString> > &keyValue)
+{
+ flushPotentialLinesWithNewlines();
+ writeIndent();
+ m_stream->write(QString("%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());
+ if (i != keyValue.size() - 1) {
+ m_stream->write(",\n");
+ } else {
+ m_stream->write("\n");
+ }
+ }
+ --m_indentDepth;
+ writeIndent();
+ m_stream->write("}\n");
+}
+
+void QmlStreamWriter::writeIndent()
+{
+ m_stream->write(QByteArray(m_indentDepth * 4, ' '));
+}
+
+void QmlStreamWriter::writePotentialLine(const QByteArray &line)
+{
+ m_pendingLines.append(line);
+ m_pendingLineLength += line.size();
+ if (m_pendingLineLength >= 80) {
+ flushPotentialLinesWithNewlines();
+ }
+}
+
+void QmlStreamWriter::flushPotentialLinesWithNewlines()
+{
+ if (m_maybeOneline)
+ m_stream->write("\n");
+ foreach (const QByteArray &line, m_pendingLines) {
+ writeIndent();
+ m_stream->write(line);
+ m_stream->write("\n");
+ }
+ m_pendingLines.clear();
+ m_pendingLineLength = 0;
+ m_maybeOneline = false;
+}
diff --git a/tools/qmlplugindump/qmlstreamwriter.h b/tools/qmlplugindump/qmlstreamwriter.h
new file mode 100644
index 0000000000..cd73aad8f2
--- /dev/null
+++ b/tools/qmlplugindump/qmlstreamwriter.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLSTREAMWRITER_H
+#define QMLSTREAMWRITER_H
+
+#include <QtCore/QIODevice>
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QPair>
+
+class QmlStreamWriter
+{
+public:
+ QmlStreamWriter(QByteArray *array);
+
+ void writeStartDocument();
+ void writeEndDocument();
+ void writeLibraryImport(const QString &uri, int majorVersion, int minorVersion, const QString &as = QString());
+ //void writeFilesystemImport(const QString &file, const QString &as = QString());
+ void writeStartObject(const QString &component);
+ void writeEndObject();
+ void writeScriptBinding(const QString &name, const QString &rhs);
+ void writeScriptObjectLiteralBinding(const QString &name, const QList<QPair<QString, QString> > &keyValue);
+ void writeArrayBinding(const QString &name, const QStringList &elements);
+ void write(const QString &data);
+
+private:
+ void writeIndent();
+ void writePotentialLine(const QByteArray &line);
+ void flushPotentialLinesWithNewlines();
+
+ int m_indentDepth;
+ QList<QByteArray> m_pendingLines;
+ int m_pendingLineLength;
+ bool m_maybeOneline;
+ QScopedPointer<QIODevice> m_stream;
+};
+
+#endif // QMLSTREAMWRITER_H
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
new file mode 100644
index 0000000000..765a9dc2fb
--- /dev/null
+++ b/tools/qmlscene/main.cpp
@@ -0,0 +1,574 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qabstractanimation.h>
+#include <QtGui/qapplication.h>
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativeview.h>
+#include <QtCore/qdir.h>
+#include <QtGui/QFormLayout>
+#include <QtGui/QComboBox>
+#include <QtGui/QCheckBox>
+#include <QtGui/QDialog>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QFileDialog>
+#include <QtGui/QGraphicsView>
+
+#include <QtDeclarative/qdeclarativeitem.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <private/qdeclarativedebughelper_p.h>
+
+// ### This should be private API
+#include <qsgitem.h>
+#include <qsgview.h>
+
+#define QT_NO_SCENEGRAPHITEM
+
+#ifndef QT_NO_SCENEGRAPHITEM
+#include "scenegraphitem.h"
+#endif
+
+#include <QtCore/qmath.h>
+
+#ifdef QML_RUNTIME_TESTING
+class RenderStatistics
+{
+public:
+ static void updateStats();
+ static void printTotalStats();
+private:
+ static QVector<qreal> timePerFrame;
+ static QVector<int> timesPerFrames;
+};
+
+QVector<qreal> RenderStatistics::timePerFrame;
+QVector<int> RenderStatistics::timesPerFrames;
+
+void RenderStatistics::updateStats()
+{
+ static QTime time;
+ static int frames;
+ static int lastTime;
+
+ if (frames == 0) {
+ time.start();
+ } else {
+ int elapsed = time.elapsed();
+ timesPerFrames.append(elapsed - lastTime);
+ lastTime = elapsed;
+
+ if (elapsed > 5000) {
+ qreal avgtime = elapsed / (qreal) frames;
+ qreal var = 0;
+ for (int i = 0; i < timesPerFrames.size(); ++i) {
+ qreal diff = timesPerFrames.at(i) - avgtime;
+ var += diff * diff;
+ }
+ var /= timesPerFrames.size();
+
+ qDebug("Average time per frame: %f ms (%i fps), std.dev: %f ms", avgtime, qRound(1000. / avgtime), qSqrt(var));
+
+ timePerFrame.append(avgtime);
+ timesPerFrames.clear();
+ time.start();
+ lastTime = 0;
+ frames = 0;
+ }
+ }
+ ++frames;
+}
+
+void RenderStatistics::printTotalStats()
+{
+ int count = timePerFrame.count();
+ if (count == 0)
+ return;
+
+ qreal minTime = 0;
+ qreal maxTime = 0;
+ qreal avg = 0;
+ for (int i = 0; i < count; ++i) {
+ minTime = minTime == 0 ? timePerFrame.at(i) : qMin(minTime, timePerFrame.at(i));
+ maxTime = qMax(maxTime, timePerFrame.at(i));
+ avg += timePerFrame.at(i);
+ }
+ avg /= count;
+
+ qDebug(" ");
+ qDebug("----- Statistics -----");
+ qDebug("Average time per frame: %f ms (%i fps)", avg, qRound(1000. / avg));
+ qDebug("Best time per frame: %f ms (%i fps)", minTime, int(1000 / minTime));
+ qDebug("Worst time per frame: %f ms (%i fps)", maxTime, int(1000 / maxTime));
+ qDebug("----------------------");
+ qDebug(" ");
+}
+#endif
+
+
+static QGLFormat getFormat()
+{
+ QGLFormat f = QGLFormat::defaultFormat();
+ f.setSampleBuffers(!qApp->arguments().contains("--no-multisample"));
+ f.setSwapInterval(qApp->arguments().contains("--nonblocking-swap") ? 0 : 1);
+ f.setStereo(qApp->arguments().contains("--stereo"));
+ return f;
+}
+
+class MyQSGView : public QSGView
+{
+public:
+ MyQSGView() : QSGView(getFormat())
+ {
+ setResizeMode(QSGView::SizeRootObjectToView);
+ }
+
+protected:
+ void paintEvent(QPaintEvent *e) {
+ QSGView::paintEvent(e);
+
+#ifdef QML_RUNTIME_TESTING
+// RenderStatistics::updateStats();
+#endif
+
+ static bool continuousUpdate = qApp->arguments().contains("--continuous-update");
+ if (continuousUpdate)
+ update();
+ }
+};
+
+class MyDeclarativeView: public QDeclarativeView
+{
+public:
+ MyDeclarativeView(QWidget *parent = 0) : QDeclarativeView(parent)
+ {
+ setResizeMode(QDeclarativeView::SizeRootObjectToView);
+ }
+
+protected:
+ void paintEvent(QPaintEvent *event)
+ {
+ QDeclarativeView::paintEvent(event);
+
+#ifdef QML_RUNTIME_TESTING
+ RenderStatistics::updateStats();
+#endif
+
+ static bool continuousUpdate = qApp->arguments().contains("--continuous-update");
+ if (continuousUpdate)
+ scene()->update();
+ }
+};
+
+#ifndef QT_NO_SCENEGRAPHITEM
+class MyGraphicsView: public QGraphicsView
+{
+public:
+ MyGraphicsView(bool clip, QWidget *parent = 0) : QGraphicsView(parent)
+ {
+ setViewport(new QGLWidget(getFormat()));
+ setScene(&scene);
+ scene.addItem(&item);
+ item.setFlag(QGraphicsItem::ItemClipsToShape, clip);
+ QGraphicsTextItem *text;
+ text = scene.addText(QLatin1String("Scene graph on graphics view."), QFont(QLatin1String("Times"), 10));
+ text->setX(5);
+ text->setY(5);
+ text->setDefaultTextColor(Qt::black);
+ text = scene.addText(QLatin1String("Scene graph on graphics view."), QFont(QLatin1String("Times"), 10));
+ text->setX(4);
+ text->setY(4);
+ text->setDefaultTextColor(Qt::yellow);
+ }
+
+ SceneGraphItem *sceneGraphItem() { return &item; }
+
+protected:
+ void paintEvent(QPaintEvent *event)
+ {
+ QGraphicsView::paintEvent(event);
+
+#ifdef QML_RUNTIME_TESTING
+ RenderStatistics::updateStats();
+#endif
+
+ static bool continuousUpdate = qApp->arguments().contains("--continuous-update");
+ if (continuousUpdate)
+ QGraphicsView::scene()->update();
+ }
+
+ QGraphicsScene scene;
+ SceneGraphItem item;
+};
+#endif
+
+struct Options
+{
+ Options()
+ : originalQml(false)
+ , originalQmlRaster(false)
+ , maximized(false)
+ , fullscreen(false)
+ , scenegraphOnGraphicsview(false)
+ , clip(false)
+ , versionDetection(true)
+ {
+ }
+
+ QUrl file;
+ bool originalQml;
+ bool originalQmlRaster;
+ bool maximized;
+ bool fullscreen;
+ bool scenegraphOnGraphicsview;
+ bool clip;
+ bool versionDetection;
+};
+
+#if defined(QMLSCENE_BUNDLE)
+Q_DECLARE_METATYPE(QFileInfo);
+QFileInfoList findQmlFiles(const QString &dirName)
+{
+ QDir dir(dirName);
+
+ QFileInfoList ret;
+ if (dir.exists()) {
+ QFileInfoList fileInfos = dir.entryInfoList(QStringList() << "*.qml",
+ QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot);
+
+ foreach (QFileInfo fileInfo, fileInfos) {
+ if (fileInfo.isDir())
+ ret += findQmlFiles(fileInfo.filePath());
+ else if (fileInfo.fileName().length() > 0 && fileInfo.fileName().at(0).isLower())
+ ret.append(fileInfo);
+ }
+ }
+
+ return ret;
+}
+
+static int displayOptionsDialog(Options *options)
+{
+ QDialog dialog;
+
+ QFormLayout *layout = new QFormLayout(&dialog);
+
+ QComboBox *qmlFileComboBox = new QComboBox(&dialog);
+ QFileInfoList fileInfos = findQmlFiles(":/bundle") + findQmlFiles("./qmlscene-resources");
+
+ foreach (QFileInfo fileInfo, fileInfos)
+ qmlFileComboBox->addItem(fileInfo.dir().dirName() + "/" + fileInfo.fileName(), QVariant::fromValue(fileInfo));
+
+ QCheckBox *originalCheckBox = new QCheckBox(&dialog);
+ originalCheckBox->setText("Use original QML viewer");
+ originalCheckBox->setChecked(options->originalQml);
+
+ QCheckBox *fullscreenCheckBox = new QCheckBox(&dialog);
+ fullscreenCheckBox->setText("Start fullscreen");
+ fullscreenCheckBox->setChecked(options->fullscreen);
+
+ QCheckBox *maximizedCheckBox = new QCheckBox(&dialog);
+ maximizedCheckBox->setText("Start maximized");
+ maximizedCheckBox->setChecked(options->maximized);
+
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
+ Qt::Horizontal,
+ &dialog);
+ QObject::connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ QObject::connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
+
+ layout->addRow("Qml file:", qmlFileComboBox);
+ layout->addWidget(originalCheckBox);
+ layout->addWidget(maximizedCheckBox);
+ layout->addWidget(fullscreenCheckBox);
+ layout->addWidget(buttonBox);
+
+ int result = dialog.exec();
+ if (result == QDialog::Accepted) {
+ QVariant variant = qmlFileComboBox->itemData(qmlFileComboBox->currentIndex());
+ QFileInfo fileInfo = variant.value<QFileInfo>();
+
+ if (fileInfo.canonicalFilePath().startsWith(":"))
+ options->file = QUrl("qrc" + fileInfo.canonicalFilePath());
+ else
+ options->file = QUrl::fromLocalFile(fileInfo.canonicalFilePath());
+ options->originalQml = originalCheckBox->isChecked();
+ options->maximized = maximizedCheckBox->isChecked();
+ options->fullscreen = fullscreenCheckBox->isChecked();
+ }
+ return result;
+}
+#endif
+
+static void checkAndAdaptVersion(const QUrl &url)
+{
+ if (!qgetenv("QMLSCENE_IMPORT_NAME").isEmpty()) {
+ return;
+ }
+
+ QString fileName = url.toLocalFile();
+ if (fileName.isEmpty())
+ return;
+
+ QFile f(fileName);
+ if (!f.open(QFile::ReadOnly | QFile::Text)) {
+ qWarning("qmlscene: failed to check version of file '%s', could not open...",
+ qPrintable(fileName));
+ return;
+ }
+
+ QRegExp quick1("import +QtQuick +1\\.");
+ QRegExp qt47("import +Qt +4\\.7");
+
+ QString envToWrite;
+ QString compat;
+
+ QTextStream stream(&f);
+ bool codeFound= false;
+ while (!codeFound && envToWrite.isEmpty()) {
+ QString line = stream.readLine();
+ if (line.contains("{"))
+ codeFound = true;
+ if (quick1.indexIn(line) >= 0) {
+ envToWrite = QLatin1String("quick1");
+ compat = QLatin1String("QtQuick 1.0");
+ } else if (qt47.indexIn(line) >= 0) {
+ envToWrite = QLatin1String("qt");
+ compat = QLatin1String("Qt 4.7");
+ }
+ }
+
+ if (!envToWrite.isEmpty()) {
+ qWarning("qmlscene: Autodetecting compatibility import \"%s\"...", qPrintable(compat));
+ if (qgetenv("QMLSCENE_IMPORT_NAME").isEmpty())
+ qputenv("QMLSCENE_IMPORT_NAME", envToWrite.toLatin1().constData());
+ }
+}
+
+static void displayFileDialog(Options *options)
+{
+ QString fileName = QFileDialog::getOpenFileName(0, "Open QML file", QString(), "QML Files (*.qml)");
+ if (!fileName.isEmpty()) {
+ QFileInfo fi(fileName);
+ options->file = QUrl::fromLocalFile(fi.canonicalFilePath());
+ }
+}
+
+static void loadDummyDataFiles(QDeclarativeEngine &engine, const QString& directory)
+{
+ QDir dir(directory+"/dummydata", "*.qml");
+ QStringList list = dir.entryList();
+ for (int i = 0; i < list.size(); ++i) {
+ QString qml = list.at(i);
+ QFile f(dir.filePath(qml));
+ f.open(QIODevice::ReadOnly);
+ QByteArray data = f.readAll();
+ QDeclarativeComponent comp(&engine);
+ comp.setData(data, QUrl());
+ QObject *dummyData = comp.create();
+
+ if(comp.isError()) {
+ QList<QDeclarativeError> errors = comp.errors();
+ foreach (const QDeclarativeError &error, errors) {
+ qWarning() << error;
+ }
+ }
+
+ if (dummyData) {
+ qWarning() << "Loaded dummy data:" << dir.filePath(qml);
+ qml.truncate(qml.length()-4);
+ engine.rootContext()->setContextProperty(qml, dummyData);
+ dummyData->setParent(&engine);
+ }
+ }
+}
+
+static void usage()
+{
+ qWarning("Usage: qmlscene [options] <filename>");
+ qWarning(" ");
+ qWarning(" options:");
+ qWarning(" --maximized ............................... run maximized");
+ qWarning(" --fullscreen .............................. run fullscreen");
+ qWarning(" --original-qml ............................ run using QGraphicsView instead of scenegraph (OpenGL engine)");
+ qWarning(" --original-qml-raster ..................... run using QGraphicsView instead of scenegraph (Raster engine)");
+ qWarning(" --no-multisample .......................... Disable multisampling (anti-aliasing)");
+ qWarning(" --continuous-update ....................... Continuously render the scene");
+ qWarning(" --nonblocking-swap ........................ Do not wait for v-sync to swap buffers");
+ qWarning(" --stereo .................................. Enable stereo on the GL context");
+#ifndef QT_NO_SCENEGRAPHITEM
+ qWarning(" --sg-on-gv [--clip] ....................... Scenegraph on graphicsview (and clip to item)");
+#endif
+ qWarning(" --no-version-detection .................... Do not try to detect the version of the .qml file");
+
+ qWarning(" ");
+ exit(1);
+}
+
+int main(int argc, char ** argv)
+{
+#ifdef Q_WS_X11
+ QApplication::setAttribute(Qt::AA_X11InitThreads);
+#endif
+
+ Options options;
+
+ QDeclarativeDebugHelper::enableDebugging();
+ QStringList imports;
+ for (int i = 1; i < argc; ++i) {
+ if (*argv[i] != '-' && QFileInfo(argv[i]).exists())
+ options.file = QUrl::fromLocalFile(argv[i]);
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--original-qml"))
+ options.originalQml = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--original-qml-raster"))
+ options.originalQmlRaster = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--maximized"))
+ options.maximized = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--fullscreen"))
+ options.fullscreen = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--sg-on-gv"))
+ options.scenegraphOnGraphicsview = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--clip"))
+ options.clip = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--no-version-detection"))
+ options.versionDetection = false;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("-i") && i + 1 < argc)
+ imports.append(QString::fromLatin1(argv[++i]));
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--help")
+ || QString::fromLatin1(argv[i]).toLower() == QLatin1String("-help")
+ || QString::fromLatin1(argv[i]).toLower() == QLatin1String("--h")
+ || QString::fromLatin1(argv[i]).toLower() == QLatin1String("-h"))
+ usage();
+ }
+
+ QApplication::setGraphicsSystem("raster");
+
+ QApplication app(argc, argv);
+ app.setApplicationName("QtQmlViewer");
+ app.setOrganizationName("Nokia");
+ app.setOrganizationDomain("nokia.com");
+
+ if (options.file.isEmpty())
+#if defined(QMLSCENE_BUNDLE)
+ displayOptionsDialog(&options);
+#else
+ displayFileDialog(&options);
+#endif
+
+ QWidget *view = 0;
+ QDeclarativeEngine *engine = 0;
+
+ int exitCode = 0;
+
+ if (!options.file.isEmpty()) {
+#ifndef QT_NO_SCENEGRAPHITEM
+ if (options.scenegraphOnGraphicsview) {
+ MyGraphicsView *gvView = new MyGraphicsView(options.clip);
+ SceneGraphItem *item = gvView->sceneGraphItem();
+ engine = item->engine();
+ for (int i = 0; i < imports.size(); ++i)
+ engine->addImportPath(imports.at(i));
+ view = gvView;
+ if (options.file.isLocalFile()) {
+ QFileInfo fi(options.file.toLocalFile());
+ loadDummyDataFiles(*engine, fi.path());
+ }
+ item->setSource(options.file);
+ } else
+#endif
+ if (!options.originalQml && !options.originalQmlRaster) {
+ if (options.versionDetection)
+ checkAndAdaptVersion(options.file);
+ QSGView *qxView = new MyQSGView();
+ engine = qxView->engine();
+ for (int i = 0; i < imports.size(); ++i)
+ engine->addImportPath(imports.at(i));
+ view = qxView;
+ if (options.file.isLocalFile()) {
+ QFileInfo fi(options.file.toLocalFile());
+ loadDummyDataFiles(*engine, fi.path());
+ }
+ qxView->setSource(options.file);
+
+ } else {
+ MyDeclarativeView *gvView = new MyDeclarativeView();
+ engine = gvView->engine();
+ for (int i = 0; i < imports.size(); ++i)
+ engine->addImportPath(imports.at(i));
+ view = gvView;
+ if (options.file.isLocalFile()) {
+ QFileInfo fi(options.file.toLocalFile());
+ loadDummyDataFiles(*engine, fi.path());
+ }
+ gvView->setSource(options.file);
+ if (!options.originalQmlRaster) {
+ QGLWidget *viewport = new QGLWidget(getFormat());
+ gvView->setViewport(viewport);
+ }
+ }
+
+ QObject::connect(engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
+
+ if (options.fullscreen)
+ view->showFullScreen();
+ else if (options.maximized)
+ view->showMaximized();
+ else
+ view->show();
+
+#ifdef Q_WS_MAC
+ view->raise();
+#endif
+
+ exitCode = app.exec();
+
+ delete view;
+
+#ifdef QML_RUNTIME_TESTING
+ RenderStatistics::printTotalStats();
+#endif
+ }
+
+ return exitCode;
+}
+
diff --git a/tools/qmlscene/qmlscene.pro b/tools/qmlscene/qmlscene.pro
new file mode 100644
index 0000000000..3849336fc8
--- /dev/null
+++ b/tools/qmlscene/qmlscene.pro
@@ -0,0 +1,20 @@
+TEMPLATE = app
+TARGET = qmlscene
+DESTDIR= ../../bin
+
+QT += declarative
+
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
+
+macx: CONFIG -= app_bundle
+
+SOURCES += main.cpp
+
+CONFIG += console
+
+symbian {
+ TARGET.EPOCHEAPSIZE = 0x20000 0x5000000
+}
+
+DEFINES += QML_RUNTIME_TESTING
diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp
index b2c7f4f730..b1a10ff6c4 100644
--- a/tools/qmlviewer/main.cpp
+++ b/tools/qmlviewer/main.cpp
@@ -156,7 +156,9 @@ void usage()
qWarning(" -P <directory> ........................... prepend to the plugin search path");
#if defined(Q_WS_MAC)
qWarning(" -no-opengl ............................... don't use a QGLWidget for the viewport");
+ qWarning(" -opengl .................................. use a QGLWidget for the viewport (default)");
#else
+ qWarning(" -no-opengl ............................... don't use a QGLWidget for the viewport (default)");
qWarning(" -opengl .................................. use a QGLWidget for the viewport");
#endif
qWarning(" -script <path> ........................... set the script to use");
@@ -375,13 +377,10 @@ static void parseCommandLineOptions(const QStringList &arguments)
} else if (arg == "-translation") {
if (lastArg) usage();
opts.translationFile = arguments.at(++i);
-#if defined(Q_WS_MAC)
} else if (arg == "-no-opengl") {
opts.useGL = false;
-#else
} else if (arg == "-opengl") {
opts.useGL = true;
-#endif
} else if (arg == "-qmlbrowser") {
opts.useNativeFileBrowser = false;
} else if (arg == "-warnings") {
@@ -522,6 +521,8 @@ QDeclarativeViewer *openFile(const QString &fileName)
int main(int argc, char ** argv)
{
+ QDeclarativeDebugHelper::enableDebugging();
+
systemMsgOutput = qInstallMsgHandler(myMessageOutput);
#if defined (Q_WS_X11) || defined (Q_WS_MAC)
diff --git a/tools/qmlviewer/qmlruntime.cpp b/tools/qmlviewer/qmlruntime.cpp
index 36915d12bf..4bae7f3ec0 100644
--- a/tools/qmlviewer/qmlruntime.cpp
+++ b/tools/qmlviewer/qmlruntime.cpp
@@ -1477,6 +1477,7 @@ void QDeclarativeViewer::setUseGL(bool useGL)
QGLFormat format = QGLFormat::defaultFormat();
#ifdef Q_WS_MAC
format.setSampleBuffers(true);
+ format.setSwapInterval(1);
#else
format.setSampleBuffers(false);
#endif
diff --git a/tools/tools.pro b/tools/tools.pro
index 2035460ce2..6d5b43a9e4 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -1,2 +1,2 @@
TEMPLATE = subdirs
-SUBDIRS += qmlviewer
+SUBDIRS += qmlviewer qmlscene qmlplugindump distfieldgen